<!DOCTYPE html>












  


<html class="theme-next pisces use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">



















  
  
  
  

  
    
    
  

  
    
      
    

    
  

  

  
    
      
    

    
  

  
    
      
    

    
  

  
    
    
    <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Monda:300,300italic,400,400italic,700,700italic|Roboto Slab:300,300italic,400,400italic,700,700italic|Lobster Two:300,300italic,400,400italic,700,700italic|PT Mono:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext">
  






<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css?v=4.7.0">

<link rel="stylesheet" href="/css/main.css?v=7.1.2">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=7.1.2">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=7.1.2">


  <link rel="icon" type="image/png" sizes="16x16" href="/favicon.ico?v=7.1.2">


  <link rel="mask-icon" href="/images/logo.svg?v=7.1.2" color="#222">







<script id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '7.1.2',
    sidebar: {"position":"left","display":"hide","offset":12,"onmobile":false,"dimmer":false},
    back2top: true,
    back2top_sidebar: false,
    fancybox: false,
    fastclick: false,
    lazyload: false,
    tabs: true,
    motion: {"enable":true,"async":true,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>


  




  <meta name="description" content="并发编程和线程池 练气期（并发编程基础）练气期一层（this）synchronized(this)和synchronized方法都是锁当前对象。">
<meta name="keywords" content="并发和多线程">
<meta property="og:type" content="article">
<meta property="og:title" content="并发编程和线程池">
<meta property="og:url" content="https://www.dudefu.tk/并发编程和线程池.html">
<meta property="og:site_name" content="The Future">
<meta property="og:description" content="并发编程和线程池 练气期（并发编程基础）练气期一层（this）synchronized(this)和synchronized方法都是锁当前对象。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://www.dudefu.tk/111公众号.jpg">
<meta property="og:image" content="https://www.dudefu.tk/111公众号.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/对象内存模型.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/线程状态图.jpg">
<meta property="og:image" content="https://www.dudefu.tk/111公众号.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/跳表.jpg">
<meta property="og:image" content="https://www.dudefu.tk/111公众号.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/jvm基本结构图.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/堆内存简图.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/复制算法.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/标记-清楚算法.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/标记-整理.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/垃圾回收的常见匹配.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/串行收集器.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/并行收集器.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/Parallel%20Scavenge%20参数.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/Serial%20Old收集器.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/Parallel%20Old%20收集器.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/CMS收集器.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/G1.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/G11.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/JVM相关命令.jpg">
<meta property="og:image" content="https://www.dudefu.tk/111公众号.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/握手和挥手.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/BIO结构.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/BIO线程池结果图.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/NIO.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/AIO执行流程图.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/Netty架构.jpg">
<meta property="og:image" content="https://www.dudefu.tk/media/1582184953(1">
<meta property="og:image" content="https://www.dudefu.tk/media/1582293141(1">
<meta property="og:image" content="https://www.dudefu.tk/media/1582293463(1">
<meta property="og:updated_time" content="2020-03-10T03:38:20.066Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="并发编程和线程池">
<meta name="twitter:description" content="并发编程和线程池 练气期（并发编程基础）练气期一层（this）synchronized(this)和synchronized方法都是锁当前对象。">
<meta name="twitter:image" content="https://www.dudefu.tk/111公众号.jpg">





  
  
  <link rel="canonical" href="https://www.dudefu.tk/并发编程和线程池">



<script id="page.configurations">
  CONFIG.page = {
    sidebar: "",
  };
</script>

  <title>并发编程和线程池 | The Future</title>
  












  <noscript>
  <style>
  .use-motion .motion-element,
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-title { opacity: initial; }

  .use-motion .logo,
  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope="" itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope="" itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">The Future</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
    
      
        <h1 class="site-subtitle" itemprop="description">Stay hungry,stay foolish.</h1>
      
    
    
  </div>

  <div class="site-nav-toggle">
    <button aria-label="切换导航栏">
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>



<nav class="site-nav">
  
    <ul id="menu" class="menu">
      
        
        
        
          
          <li class="menu-item menu-item-home">

    
    
    
      
    

    
      
    

    <a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i> <br>首页</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-archives">

    
    
    
      
    

    
      
    

    <a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i> <br>归档<span class="badge">125</span></a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-categories">

    
    
    
      
    

    
      
    

    <a href="/categories" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i> <br>分类<span class="badge">15</span></a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-tags">

    
    
    
      
    

    
      
    

    <a href="/tags" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i> <br>标签<span class="badge">63</span></a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-something">

    
    
    
      
    

    
      
    

    <a href="/something" rel="section"><i class="menu-item-icon fa fa-fw fa-paper-plane"></i> <br>干货</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-about">

    
    
    
      
    

    
      
    

    <a href="/about/" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i> <br>关于</a>

  </li>

      
      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br>搜索</a>
        </li>
      
    </ul>
  

  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



  



</div>
    </header>

    


    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          
            

          
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  
    <div class="reading-progress-bar"></div>
  

  <article class="post post-type-normal" itemscope="" itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://www.dudefu.tk/并发编程和线程池.html">

    <span hidden itemprop="author" itemscope="" itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Daniel X">
      <meta itemprop="description" content="專注于大数据技術，分享干货">
      <meta itemprop="image" content="https://hexoblog-1254111960.cos.ap-guangzhou.myqcloud.com/HexoBlog-tou.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="The Future">
    </span>

    
      <header class="post-header">

        
        
          <h2 class="post-title" itemprop="name headline">并发编程和线程池

              
            
          </h2>
        

        <div class="post-meta">
          <span class="post-time">

            
            
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              

              
                
              

              <time title="创建时间：2020-03-06 14:37:48" itemprop="dateCreated datePublished" datetime="2020-03-06T14:37:48+08:00">2020-03-06</time>
            

            
              

              
                
                <span class="post-meta-divider">|</span>
                

                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                
                  <span class="post-meta-item-text">更新于</span>
                
                <time title="修改时间：2020-03-10 11:38:20" itemprop="dateModified" datetime="2020-03-10T11:38:20+08:00">2020-03-10</time>
              
            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope="" itemtype="http://schema.org/Thing"><a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a></span>

                
                
              
            </span>
          

          
            
            
              
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
            
                <span class="post-meta-item-text">评论数：</span>
                <a href="/并发编程和线程池.html#comments" itemprop="discussionUrl">
                  <span class="post-comments-count valine-comment-count" data-xid="/并发编程和线程池.html" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          
            <span id="/并发编程和线程池.html" class="leancloud_visitors" data-flag-title="并发编程和线程池">
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              
                <span class="post-meta-item-text">阅读次数：</span>
              
                <span class="leancloud-visitors-count"></span>
            </span>
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>并发编程和线程池</p>
<h2 id="练气期（并发编程基础）"><a href="#练气期（并发编程基础）" class="headerlink" title="练气期（并发编程基础）"></a>练气期（并发编程基础）</h2><h3 id="练气期一层（this）"><a href="#练气期一层（this）" class="headerlink" title="练气期一层（this）"></a>练气期一层（this）</h3><p><em>synchronized(this)和synchronized方法都是锁当前对象。</em></p>
<a id="more"></a>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> count = <span class="number">0</span>;  <span class="comment">// 存在堆中</span></span><br><span class="line">    <span class="keyword">private</span> Object o = <span class="keyword">new</span> Object();    <span class="comment">// 存在堆中</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 多个线程都能找到的，都能访问的对象叫临界资源对象</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSync1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (o) &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName()</span><br><span class="line">                    + <span class="string">" count = "</span> + count++);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testSync2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (<span class="keyword">this</span>) &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName()</span><br><span class="line">                    + <span class="string">" count = "</span> + count++);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">testSync3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()</span><br><span class="line">                + <span class="string">" count = "</span> + count++);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_01 t = <span class="keyword">new</span> Test_01();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.testSync3();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.testSync3();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期二层（static）"><a href="#练气期二层（static）" class="headerlink" title="练气期二层（static）"></a>练气期二层（static）</h3><p><em>静态同步方法，锁的是当前类型的类对象。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_02</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> staticCount = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">testSync4</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() </span><br><span class="line">                + <span class="string">" staticCount = "</span> + staticCount++);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testSync5</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span>(Test_02.class)&#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() </span><br><span class="line">                    + <span class="string">" staticCount = "</span> + staticCount++);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期三层（原子性）"><a href="#练气期三层（原子性）" class="headerlink" title="练气期三层（原子性）"></a>练气期三层（原子性）</h3><p><em>加锁的目的就是为了保证操作的原子性</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_03</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="comment">/*synchronized*/</span> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()</span><br><span class="line">                + <span class="string">" count = "</span> + count++);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Test_03 t = <span class="keyword">new</span> Test_03();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(t, <span class="string">"Thread - "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期四层（同步与非同步方法间调用）"><a href="#练气期四层（同步与非同步方法间调用）" class="headerlink" title="练气期四层（同步与非同步方法间调用）"></a>练气期四层（同步与非同步方法间调用）</h3><p><em>同步方法只影响锁定同一个锁对象的同步方法。不影响其他线程调用非同步方法，或调用其他锁资源的同步方法。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_04</span> </span>&#123;</span><br><span class="line">    Object o = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123; <span class="comment">// 重量级的访问操作。</span></span><br><span class="line">        System.out.println(<span class="string">"public synchronized void m1() start"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"public synchronized void m1() end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">m3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (o) &#123;</span><br><span class="line">            System.out.println(<span class="string">"public void m3() start"</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1500</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">"public void m3() end"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"public void m2() start"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">1500</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"public void m2() end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread01</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">MyThread01</span><span class="params">(<span class="keyword">int</span> i, Test_04 t)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.i = i;</span><br><span class="line">            <span class="keyword">this</span>.t = t;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> i;</span><br><span class="line">        Test_04 t;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (i == <span class="number">0</span>) &#123;</span><br><span class="line">                t.m1();</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (i &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                t.m2();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                t.m3();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Test_04 t = <span class="keyword">new</span> Test_04();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Test_04.MyThread01(<span class="number">0</span>, t)).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Test_04.MyThread01(<span class="number">1</span>, t)).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Test_04.MyThread01(-<span class="number">1</span>, t)).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期五层（存在原子性问题）"><a href="#练气期五层（存在原子性问题）" class="headerlink" title="练气期五层（存在原子性问题）"></a>练气期五层（存在原子性问题）</h3><p><em>同步方法只能保证当前方法的原子性，不能保证多个业务方法之间的互相访问的原子性。一般来说，商业项目中，不考虑业务逻辑上的脏读问题。如你买东西下订单后，提示订单已下，查询时候，可能看不到。一般我们只关注数据脏读。但是在金融领域，保险领域严格要求。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_05</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">double</span> d = <span class="number">0.0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m1</span><span class="params">(<span class="keyword">double</span> d)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 相当于复杂的业务逻辑代码。</span></span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.d = d;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">m2</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.d;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_05 t = <span class="keyword">new</span> Test_05();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m1(<span class="number">100</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">        System.out.println(t.m2());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(t.m2());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期六层（锁可重入）"><a href="#练气期六层（锁可重入）" class="headerlink" title="练气期六层（锁可重入）"></a>练气期六层（锁可重入）</h3><p><em>同一个线程，多次调用同步代码，锁定同一个锁对象，可重入。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_06</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span></span>&#123; <span class="comment">// 锁this</span></span><br><span class="line">        System.out.println(<span class="string">"m1 start"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        m2();</span><br><span class="line">        System.out.println(<span class="string">"m1 end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span></span>&#123; <span class="comment">// 锁this</span></span><br><span class="line">        System.out.println(<span class="string">"m2 start"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"m2 end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Test_06().m1();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期七层（调用父类的同步方法）"><a href="#练气期七层（调用父类的同步方法）" class="headerlink" title="练气期七层（调用父类的同步方法）"></a>练气期七层（调用父类的同步方法）</h3><p><em>子类同步方法覆盖父类同步方法，可以指定调用父类的同步方法， 相当于锁的重入。父类的方法 &lt;&lt;==&gt;&gt; 本类的方法</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_07</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Super Class m start"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"Super Class m end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Sub_Test_07().m();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Sub_Test_07</span> <span class="keyword">extends</span> <span class="title">Test_07</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Sub Class m start"</span>);</span><br><span class="line">        <span class="keyword">super</span>.m();</span><br><span class="line">        System.out.println(<span class="string">"Sub Class m end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期八层（锁与异常）"><a href="#练气期八层（锁与异常）" class="headerlink" title="练气期八层（锁与异常）"></a>练气期八层（锁与异常）</h3><p><em>当同步方法中发生异常的时候，自动释放锁资源，不会影响其他线程的执行。我们需要注意的是在同步业务逻辑中，如果发生异常如何处理——— try/catch 。如存钱时，发送网络中断，查询的时候查到多少钱，存的钱要返还</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_08</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">" - start"</span>);</span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">            i++;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">" - "</span> + i);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">/*if(i == 5)&#123;</span></span><br><span class="line"><span class="comment">                i = 1/0;</span></span><br><span class="line"><span class="comment">            &#125;*/</span></span><br><span class="line">            <span class="comment">//模拟存钱，中断处理</span></span><br><span class="line">            <span class="keyword">if</span> (i == <span class="number">5</span>) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    i = <span class="number">1</span> / <span class="number">0</span>;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    i = <span class="number">0</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_08 t = <span class="keyword">new</span> Test_08();</span><br><span class="line">        <span class="comment">// 锁的是当前对象</span></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"t1"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"t2"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期九层（volatile）"><a href="#练气期九层（volatile）" class="headerlink" title="练气期九层（volatile）"></a>练气期九层（volatile）</h3><p><em>cpu默认查询cpu的高速缓存区域，CPU中每一个核都有自己的缓存，当cpu有中断的时候，他可能清空高速缓存区域数据，重新从内存中读取数据。volatile改变内存中的数据，通知底层OS系统，每次使用b的时候，最好看下内存数据是否发生变动。即volatile做的是一个通知OS系统的作。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_09</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">boolean</span> b = <span class="keyword">true</span>;    <span class="comment">//线程可见性问题</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"start"</span>);</span><br><span class="line">        <span class="keyword">while</span>(b)&#123;&#125;</span><br><span class="line">        System.out.println(<span class="string">"end"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_09 t = <span class="keyword">new</span> Test_09();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        t.b = <span class="keyword">false</span>;    <span class="comment">//堆空间的对象，线程共享</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><em>volatile的非原子性问题，只能保证可见性，不能保证原子性。</em></p>
<p><em>那什么时候使用volatile？棋牌室的人数，新增的人有一个线程去+1。这是可以使用volatile</em></p>
<p><em>join()多个线程在运行结束时，我把多个线程再main线程的位置连在一起，当其他线程都结束，即保证在所有线程循环执行+1后，再执行main线程打印。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_10</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*synchronized*/</span> <span class="function"><span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;    <span class="comment">//保证原子性的解决方法是使用synchronized或者是Atomic</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10000</span>; i++) &#123;</span><br><span class="line">            count++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_10 t = <span class="keyword">new</span> Test_10();</span><br><span class="line">        List&lt;Thread&gt; threads = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            threads.add(<span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    t.m();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Thread thread : threads) &#123;</span><br><span class="line">            thread.start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Thread thread : threads) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                thread.join();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(t.count);    <span class="comment">//理论上是10w。实际少于这个数</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期十层（AtomicXxx）"><a href="#练气期十层（AtomicXxx）" class="headerlink" title="练气期十层（AtomicXxx）"></a>练气期十层（AtomicXxx）</h3><p><em>什么时候有原子性，没有可见性？</em></p>
<p><em>答：所谓原子性是指多个线程访问一个变量时，其结果必须保证正确性。</em>所谓可见性是指多线程间可以看最终结果的变量</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_11</span> </span>&#123;</span><br><span class="line">    AtomicInteger count = <span class="keyword">new</span> AtomicInteger(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10000</span>; i++) &#123;</span><br><span class="line">            <span class="comment">/*if(count.get() &lt; 1000)*/</span></span><br><span class="line">            count.incrementAndGet();    <span class="comment">//相当于++count,count.getAndAccumulate()是count++;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_11 t = <span class="keyword">new</span> Test_11();</span><br><span class="line">        List&lt;Thread&gt; threads = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            threads.add(<span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    t.m();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Thread thread : threads) &#123;</span><br><span class="line">            thread.start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Thread thread : threads) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                thread.join();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(t.count.intValue());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期十一层（锁对象变更）"><a href="#练气期十一层（锁对象变更）" class="headerlink" title="练气期十一层（锁对象变更）"></a>练气期十一层（锁对象变更）</h3><ul>
<li>同步代码一旦加锁后，那么会有一个临时的锁引用指向锁对象，和真实的引用无直接关联。在锁未释放之前，修改锁引用，不会影响同步代码的执行。</li>
<li>我们打印的是Test_13中的o。不是锁引用的_O;下面synchronized锁的是两个对象。打印的是同一个对象。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_13</span> </span>&#123;</span><br><span class="line">    Object o = <span class="keyword">new</span> Object();    <span class="comment">//变量引用</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">a</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">/*</span></span><br><span class="line"><span class="comment">             * return i -&gt;</span></span><br><span class="line"><span class="comment">             * int _returnValue = i; // 0;</span></span><br><span class="line"><span class="comment">             * return _returnValue;</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            i = <span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">" start"</span>);</span><br><span class="line">        <span class="keyword">synchronized</span> (o) &#123;    <span class="comment">//计算变量引用与变量引用不是一回事</span></span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">" - "</span> + o);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_13 t = <span class="keyword">new</span> Test_13();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"thread1"</span>).start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        Thread thread2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"thread2"</span>);</span><br><span class="line">        t.o = <span class="keyword">new</span> Object();</span><br><span class="line">        thread2.start();    <span class="comment">//更改临界资源对象</span></span><br><span class="line"></span><br><span class="line">        System.out.println(t.i);</span><br><span class="line">        System.out.println(t.a());</span><br><span class="line">        System.out.println(t.i);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期十二层（CountDownLatch）"><a href="#练气期十二层（CountDownLatch）" class="headerlink" title="练气期十二层（CountDownLatch）"></a>练气期十二层（CountDownLatch）</h3><ul>
<li>不会进入等待队列，可以和锁混合使用，或替代锁的功能。</li>
<li>一次性在门上挂多个锁。</li>
<li>作用如：init对象的时候有一个前后顺序的问题。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_15</span> </span>&#123;</span><br><span class="line">    CountDownLatch latch = <span class="keyword">new</span> CountDownLatch(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            latch.await();<span class="comment">// 等待门闩开放。</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"m1() method"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (latch.getCount() != <span class="number">0</span>) &#123;</span><br><span class="line">                System.out.println(<span class="string">"latch count : "</span> + latch.getCount());</span><br><span class="line">                latch.countDown(); <span class="comment">// 减门闩上的锁。</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">"m2() method : "</span> + i);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_15 t = <span class="keyword">new</span> Test_15();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m1();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m2();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="练气期大圆满"><a href="#练气期大圆满" class="headerlink" title="练气期大圆满"></a>练气期大圆满</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_14</span> </span>&#123;</span><br><span class="line">    String s1 = <span class="string">"hello"</span>;</span><br><span class="line">    String s2 = <span class="keyword">new</span> String(<span class="string">"hello"</span>); <span class="comment">// new关键字，一定是在堆中创建一个新的对象。</span></span><br><span class="line">    Integer i1 = <span class="number">1</span>;    <span class="comment">// i1与i2是同一个变量，在常量池中，new是放在堆内存</span></span><br><span class="line">    Integer i2 = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (i1) &#123;    <span class="comment">//s1与s2</span></span><br><span class="line">            System.out.println(<span class="string">"m1()"</span>);</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (i2) &#123;</span><br><span class="line">            System.out.println(<span class="string">"m2()"</span>);</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_14 t = <span class="keyword">new</span> Test_14();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m1();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m2();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>自定义容器，提供新增元素（add）和获取元素数量（size）方法。启动两个线程。线程1向容器中新增10个数据。线程2监听容器元素数量，当容器元素数量为5时，线程2输出信息并终止。</strong></p>
<ol>
<li>使用volatile</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_01_Container t = <span class="keyword">new</span> Test_01_Container();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                    System.out.println(<span class="string">"add Object to Container "</span> + i);</span><br><span class="line">                    t.add(<span class="keyword">new</span> Object());</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (t.size() == <span class="number">5</span>) &#123;</span><br><span class="line">                        System.out.println(<span class="string">"size = 5"</span>);</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test_01_Container</span> </span>&#123;</span><br><span class="line">    <span class="keyword">volatile</span> List&lt;Object&gt; container = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(Object o)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.container.add(o);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.container.size();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol>
<li>使用synchronized和wait(), 调用wait()将释放锁，并且进入等待队列中，生产者与消费者模型</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_02</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_02_Container t = <span class="keyword">new</span> Test_02_Container();</span><br><span class="line">        <span class="keyword">final</span> Object lock = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (lock) &#123;</span><br><span class="line">                    <span class="keyword">if</span>(t.size() != <span class="number">5</span>)&#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            lock.wait(); <span class="comment">// 线程进入等待队列。</span></span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">"size = 5"</span>);</span><br><span class="line">                    lock.notifyAll(); <span class="comment">// 唤醒其他等待线程</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (lock) &#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">                        System.out.println(<span class="string">"add Object to Container "</span> + i);</span><br><span class="line">                        t.add(<span class="keyword">new</span> Object());</span><br><span class="line">                        <span class="keyword">if</span>(t.size() == <span class="number">5</span>)&#123;</span><br><span class="line">                            lock.notifyAll();</span><br><span class="line">                            <span class="keyword">try</span> &#123;</span><br><span class="line">                                lock.wait();</span><br><span class="line">                            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                                e.printStackTrace();</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test_02_Container</span></span>&#123;</span><br><span class="line">    List&lt;Object&gt; container = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(Object o)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.container.add(o);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.container.size();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol>
<li>使用门闩避免进入等待队列，效率更高。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_03</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_03_Container t = <span class="keyword">new</span> Test_03_Container();</span><br><span class="line">        <span class="keyword">final</span> CountDownLatch latch = <span class="keyword">new</span> CountDownLatch(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">if</span>(t.size() != <span class="number">5</span>)&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        latch.await(); <span class="comment">// 等待门闩的开放。 不是进入等待队列</span></span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(<span class="string">"size = 5"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">                    System.out.println(<span class="string">"add Object to Container "</span> + i);</span><br><span class="line">                    t.add(<span class="keyword">new</span> Object());</span><br><span class="line">                    <span class="keyword">if</span>(t.size() == <span class="number">5</span>)&#123;</span><br><span class="line">                        latch.countDown(); <span class="comment">// 门闩-1</span></span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test_03_Container</span></span>&#123;</span><br><span class="line">    List&lt;Object&gt; container = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(Object o)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.container.add(o);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.container.size();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><em>小编是一枚Java Coder，业余写文章，现主营微信公众号《Java患者》，喜欢的话关注我的公众号或者加我微信我们一起学习Java</em></p>
<p><img src="\111公众号.jpg" alt=""></p>
<h2 id="筑基期（ReentrantLock）"><a href="#筑基期（ReentrantLock）" class="headerlink" title="筑基期（ReentrantLock）"></a>筑基期（ReentrantLock）</h2><h3 id="筑基初期（lock等待锁）"><a href="#筑基初期（lock等待锁）" class="headerlink" title="筑基初期（lock等待锁）"></a>筑基初期（lock等待锁）</h3><ul>
<li>concurrent是jdk1.5后的包，避免synchronized的出现而设计出来的一种锁机制。</li>
<li>ReentrantLock 重入锁，在一个对象上加一个标记信息，这个标记信息代表锁机制。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01</span> </span>&#123;</span><br><span class="line">    Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            lock.lock(); <span class="comment">// 加锁</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                System.out.println(<span class="string">"m1() method "</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock(); <span class="comment">// 解锁</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        System.out.println(<span class="string">"m2() method"</span>);</span><br><span class="line">        lock.unlock();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_01 t = <span class="keyword">new</span> Test_01();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m1();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m2();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="筑基中期（tryLock尝试锁）"><a href="#筑基中期（tryLock尝试锁）" class="headerlink" title="筑基中期（tryLock尝试锁）"></a>筑基中期（tryLock尝试锁）</h3><p><em>尝试锁有阻塞和非阻塞两种</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_02</span> </span>&#123;</span><br><span class="line">    Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            lock.lock();</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                System.out.println(<span class="string">"m1() method "</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(InterruptedException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">boolean</span> isLocked = <span class="keyword">false</span>;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="comment">// 尝试锁， 如果有锁，无法获取锁标记，返回false。</span></span><br><span class="line">            <span class="comment">// 非阻塞，如果获取锁标记，返回true</span></span><br><span class="line">            <span class="comment">// isLocked = lock.tryLock();</span></span><br><span class="line"></span><br><span class="line">            <span class="comment">// 阻塞尝试锁，阻塞参数代表的时长，尝试获取锁标记。</span></span><br><span class="line">            <span class="comment">// 如果超时，不等待。直接返回。</span></span><br><span class="line">            isLocked = lock.tryLock(<span class="number">5</span>, TimeUnit.SECONDS); </span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span>(isLocked)&#123;</span><br><span class="line">                System.out.println(<span class="string">"m2() method synchronized"</span>);</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                System.out.println(<span class="string">"m2() method unsynchronized"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(isLocked)&#123;</span><br><span class="line">                <span class="comment">// 尝试锁在解除锁标记的时候，一定要判断是否获取到锁标记。</span></span><br><span class="line">                <span class="comment">// 如果当前线程没有获取到锁标记，会抛出异常。</span></span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_02 t = <span class="keyword">new</span> Test_02();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m1();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m2();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="筑基后期（lockInterruptibly可打断锁）"><a href="#筑基后期（lockInterruptibly可打断锁）" class="headerlink" title="筑基后期（lockInterruptibly可打断锁）"></a>筑基后期（lockInterruptibly可打断锁）</h3><ul>
<li>阻塞状态有3种： 包括普通阻塞（不释放锁），等待队列（释放锁），锁池队列。<ul>
<li>普通阻塞： sleep(10000)， 可以被打断。调用thread.interrupt()方法，可以打断阻塞状态，抛出异常。</li>
<li>等待队列： wait()方法被调用，也是一种阻塞状态，只能由notify唤醒。无法打断。</li>
<li>锁池队列： 执行过程中，遇到同步代码，无法获取锁标记。不是所有的锁池队列都可被打断。<ul>
<li>使用ReentrantLock的lock方法，获取锁标记的时候，如果需要阻塞等待锁标记，无法被打断。</li>
<li>使用ReentrantLock的lockInterruptibly方法，获取锁标记的时候，如果需要阻塞等待，可以被打断。</li>
</ul>
</li>
</ul>
</li>
<li>可打断锁意义：软件锁死了，无响应，去去任务管理器结束任务</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_03</span> </span>&#123;</span><br><span class="line">    Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            lock.lock();</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                System.out.println(<span class="string">"m1() method "</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 线程执行到这里，本来是不能获得锁标记的，要进入等待队列的。</span></span><br><span class="line">            <span class="comment">// 当通过调用当前线程的interrupt()，通过打断当前线程，抛出异常，使线程被唤醒，阻塞结束</span></span><br><span class="line">            lock.lockInterruptibly(); <span class="comment">// 可尝试打断的，阻塞等待锁。可以被其他的线程打断阻塞状态</span></span><br><span class="line">            System.out.println(<span class="string">"m2() method"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// 被打断的异常，被打断与唤醒、阻塞结束都是不一样的</span></span><br><span class="line">            <span class="comment">// sleep任何一个线程都可以把他打断，强行唤醒</span></span><br><span class="line">            <span class="comment">// 如果是lock不可被打断的</span></span><br><span class="line">            <span class="comment">// 如果是lockInterruptibly，阻塞等待这把锁，类似sleep，可以通过interrupt()打断</span></span><br><span class="line">            System.out.println(<span class="string">"m2() method interrupted"</span>);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_03 t = <span class="keyword">new</span> Test_03();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m1();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                t.m2();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t2.start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 不调用interrupt()方法，t2最后可以获得锁，继续执行</span></span><br><span class="line">        t2.interrupt();<span class="comment">// 打断t2线程，锁的位置会抛出异常。</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="筑基圆满（公平锁）"><a href="#筑基圆满（公平锁）" class="headerlink" title="筑基圆满（公平锁）"></a>筑基圆满（公平锁）</h3><ul>
<li>在cpu和os中本身线程竞争锁标记是不公平的，不考虑线程的等待时间的。</li>
<li>运用在轮询的场景，如打牌。</li>
<li>需要效果一部分的cpu资源计算等待的时间，性能有所降低。要仅能少用，并发量在10之内。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_04</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        TestReentrantlock t = <span class="keyword">new</span> TestReentrantlock();</span><br><span class="line">        <span class="comment">//TestSync t = new TestSync();</span></span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(t);</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(t);</span><br><span class="line">        t1.start();</span><br><span class="line">        t2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestReentrantlock</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 定义一个公平锁</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> ReentrantLock lock = <span class="keyword">new</span> ReentrantLock(<span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            lock.lock();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">" get lock"</span>);</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestSync</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="comment">//不公平的</span></span><br><span class="line">            <span class="keyword">synchronized</span> (<span class="keyword">this</span>) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">" get lock in TestSync"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><em>小编是一枚Java Coder，业余写文章，现主营微信公众号《Java患者》，喜欢的话关注我的公众号或者加我微信我们一起学习Java</em></p>
<p><img src="\111公众号.jpg" alt=""></p>
<h2 id="金丹期"><a href="#金丹期" class="headerlink" title="金丹期"></a>金丹期</h2><h3 id="金丹初期（生产者-amp-消费者）"><a href="#金丹初期（生产者-amp-消费者）" class="headerlink" title="金丹初期（生产者&amp;消费者）"></a>金丹初期（生产者&amp;消费者）</h3><ul>
<li>ReenTrantLock建议应用在同步方式，相对效率比synchronized高，量级较轻。</li>
<li>synchronized在JDK1.5版本尝试优化，到JDK1.7后，优化效率已经非常好了。在绝对效率上不比ReenTrantLock差多少。</li>
<li>使用ReenTrantLock必须释放锁标记。一般在finally代码块释放锁标记的。</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">练习（生产者消费者模式）：</span><br><span class="line">自定义同步容器，容器容量上限为10。可以在多线程中应用，并保证数据线程安全。</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestContainer01</span>&lt;<span class="title">E</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> LinkedList&lt;E&gt; list = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> MAX = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">int</span> <span class="title">getCount</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> count;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">put</span><span class="params">(E e)</span></span>&#123;</span><br><span class="line">        <span class="keyword">while</span>(list.size() == MAX)&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">this</span>.wait();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</span><br><span class="line">                e1.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        list.add(e);</span><br><span class="line">        count++;</span><br><span class="line">        <span class="keyword">this</span>.notifyAll();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> E <span class="title">get</span><span class="params">()</span></span>&#123;</span><br><span class="line">        E e = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">while</span>(list.size() == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                <span class="keyword">this</span>.wait();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</span><br><span class="line">                e1.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        e = list.removeFirst();</span><br><span class="line">        count--;</span><br><span class="line">        <span class="keyword">this</span>.notifyAll();</span><br><span class="line">        <span class="keyword">return</span> e;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> TestContainer01&lt;String&gt; c = <span class="keyword">new</span> TestContainer01&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">5</span>; j++)&#123;</span><br><span class="line">                        System.out.println(c.get());</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"consumer"</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">25</span>; j++)&#123;</span><br><span class="line">                        c.put(<span class="string">"container value "</span> + j); </span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"producer"</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>使用ReentrantLock完成生产者-消费者</p>
<ul>
<li>Condition， 为Lock增加条件。当条件满足时（生成了或者是被消费），做什么事情，如加锁或解锁。如等待或唤醒</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestContainer02</span>&lt;<span class="title">E</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> LinkedList&lt;E&gt; list = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> MAX = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">private</span> Condition producer = lock.newCondition();</span><br><span class="line">    <span class="keyword">private</span> Condition consumer = lock.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getCount</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> count;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">put</span><span class="params">(E e)</span></span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(list.size() == MAX)&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">" 等待。。。"</span>);</span><br><span class="line">                <span class="comment">// 进入等待队列。释放锁标记。</span></span><br><span class="line">                <span class="comment">// 借助条件，进入的等待队列。</span></span><br><span class="line">                producer.await();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">" put 。。。"</span>);</span><br><span class="line">            list.add(e);</span><br><span class="line">            count++;</span><br><span class="line">            <span class="comment">// 借助条件，唤醒所有的消费者。</span></span><br><span class="line">            consumer.signalAll();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</span><br><span class="line">            e1.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> E <span class="title">get</span><span class="params">()</span></span>&#123;</span><br><span class="line">        E e = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(list.size() == <span class="number">0</span>)&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">" 等待。。。"</span>);</span><br><span class="line">                <span class="comment">// 借助条件，消费者进入等待队列</span></span><br><span class="line">                consumer.await();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">" get 。。。"</span>);</span><br><span class="line">            e = list.removeFirst();</span><br><span class="line">            count--;</span><br><span class="line">            <span class="comment">// 借助条件，唤醒所有的生产者</span></span><br><span class="line">            producer.signalAll();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</span><br><span class="line">            e1.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> e;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> TestContainer02&lt;String&gt; c = <span class="keyword">new</span> TestContainer02&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">5</span>; j++)&#123;</span><br><span class="line">                        System.out.println(c.get());</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"consumer"</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</span><br><span class="line">            e1.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">25</span>; j++)&#123;</span><br><span class="line">                        c.put(<span class="string">"container value "</span> + j); </span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"producer"</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="金丹中期（锁的底层实现）"><a href="#金丹中期（锁的底层实现）" class="headerlink" title="金丹中期（锁的底层实现）"></a>金丹中期（锁的底层实现）</h3><p>​        <em>Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。同步方法 并不是由 monitor enter 和 monitor exit 指令来实现同步的，而是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED 标志来隐式实现的。注：monitor enter 和 monitor exit 指令是C语言的内容。</em></p>
<p><strong>对象的内存模型</strong>（一个对象包含3部分，没有方法，方法是在方法区域中的）</p>
<p><img src="\media\对象内存模型.jpg" alt="对象内存模型"></p>
<ul>
<li>对象头：存储对象的 hashCode、锁信息或分代年龄或 GC 标志，类型指针指向对象的类元数据，JVM 通过这个指针确定该对象是哪个类的实例等信息。（关注锁信息）</li>
<li>实例变量：存放类的属性数据信息，包括父类的属性信息</li>
<li>填充数据：由于虚拟机要求对象起始地址必须是 8 字节的整数倍。填充数据不是必须存在的，仅仅是为了字节对齐</li>
<li>monitor在栈中，但不是在线程栈中。</li>
<li>_Owner指向线程。</li>
</ul>
<p>​        <em>当线程在对象上加锁时，对象头都会指向monitor，记录锁信息。当执行 synchronized 同步方法或同步代码块时，会在对象头中记录锁标记，锁标记指向的是 monitor 对象（也称为管程或监视器锁）的起始地址。每个对象都存在着一个 monitor 与之关联，对象与其 monitor 之间的关系有存在多种实现方式，如 monitor 可以与对象一起创建销毁或当线程试图获取对象锁时自动生成，但当一个 monitor 被某个线程持有后，它便处于锁定状态。</em></p>
<p>​        <em>另外的线程想获取对象头中的锁信息的时候，会发现对象头中已经记录一把锁（monitor），他就获取不到。monitor是互斥的，对象头记录的monitor就不会分配给其他线程了，此时这个线程就会进入阻塞状态。</em>当执行中的线程发生异常，或者是释放锁标记，对象头的锁信息就会释放它记录的monitor。阻塞状态的线程就会弹出来争夺对象中的锁信息，重新在锁信息中记录monitor。</p>
<p>​        <em>ObjectMonitor 中有两个队列，_WaitSet 和 _EntryList，以及_Owner 标记。其中_WaitSet是用于管理等待队列(wait)线程的，_EntryList 是用于管理锁池阻塞线程的，_Owner 标记用于记录当前执行线程。</em></p>
<p><strong>线程状态图</strong></p>
<p><img src="\media\线程状态图.jpg" alt="线程状态图"></p>
<p>​        当多线程并发访问同一个同步代码时，首先会进入_EntryList，当线程获取锁标记后，monitor 中的_Owner 记录此线程，并在 monitor 中的计数器执行递增计算（+1），代表锁定，其他线程在_EntryList 中继续阻塞。若执行线程调用 wait 方法，则 monitor 中的计数器执行赋值为 0 计算，并将_Owner 标记赋值为 null，代表放弃锁，执行线程进如_WaitSet 中阻塞。若执行线程调用 notify/notifyAll 方法，_WaitSet 中的线程被唤醒，进入_EntryList 中阻塞，等待获取锁标记。若执行线程的同步代码执行结束，同样会释放锁标记，monitor 中的_Owner标记赋值为 null，且计数器赋值为 0 计算。</p>
<p>​        interrupt() 方法可以任何打断阻塞状态的线程，以抛异常的代价。</p>
<p>​        InterruptedException异常是阻塞异常。阻塞中的线程抛出的。</p>
<p><strong>锁的重入</strong></p>
<p>​        在 Java 中，同步锁是可以重入的。只有同一线程调用同步方法或执行同步代码块，对同一个对象加锁时才可重入。<br>​        当线程持有锁时，会在 monitor 的计数器中执行递增计算，若当前线程调用其他同步代码，且同步代码的锁对象相同时，monitor 中的计数器继续递增。每个同步代码执行结束，monitor 中的计数器都会递减，直至所有同步代码执行结束，monitor 中的计数器为 0 时，释放锁标记，_Owner 标记赋值为 null。</p>
<h3 id="金丹后期（锁的种类）"><a href="#金丹后期（锁的种类）" class="headerlink" title="金丹后期（锁的种类）"></a>金丹后期（锁的种类）</h3><ul>
<li>Java 中锁的种类包括偏向锁，自旋锁，轻量级锁，重量级锁。</li>
<li>锁的使用方式先提供偏向锁，如果不满足的时候，升级为轻量级锁，再不满足，升级为重量级锁。自旋锁是一个过渡的锁状态，不是一种实际的锁类型。锁只能升级，不能降级。</li>
<li>在<strong>金丹初期</strong>提到的就是重量级锁。</li>
</ul>
<p><strong>偏向锁：</strong></p>
<p>​        是一种编译解释锁。如果代码中不可能出现多线程并发争抢同一个锁的时候，JVM 编译代码，解释执行的时候，会自动的放弃同步信息。消除 synchronized 的同步代码结果。使用锁标记的形式记录锁状态。在 Monitor 中有变量 ACC_SYNCHRONIZED。当变量值使用的时候，代表偏向锁锁定。可以避免锁的争抢和锁池状态的维护。提高JVM解释效率。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Object o = <span class="keyword">new</span> Object();</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">m</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    o = <span class="keyword">new</span> Object();</span><br><span class="line">    <span class="keyword">synchronized</span> (o) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>轻量级锁：</strong></p>
<p>​        是一个过渡锁。当偏向锁不满足，也就是有多线程并发访问，锁定同一个对象的时候，先提升为轻量级锁。也是使用标记 ACC_SYNCHRONIZED 标记记录的。ACC_UNSYNCHRONIZED 标记记录未获取到锁信息的线程。就是只有两个线程争抢锁标记的时候，优先使用轻量级锁。A线程和monitor有直接关联的。B线程不记录monitor，是monitor记录B线程，线程A结束后，B两个线程才找到monitor。也可能出现重量级锁。</p>
<p><strong>自旋锁</strong>：</p>
<p>​        是一个过渡锁，是偏向锁和轻量级锁的过渡。当获取锁的过程中，未获取到。为了提高效率，JVM 自动执行若干次空循环，再次申请锁，而不是进入阻塞状态的情况。称为自旋锁。自旋锁提高效率就是避免线程状态的变更。</p>
<h3 id="金丹圆满（ThreadLocal）"><a href="#金丹圆满（ThreadLocal）" class="headerlink" title="金丹圆满（ThreadLocal）"></a>金丹圆满（ThreadLocal）</h3><ul>
<li>就是一个Map。key 是Thread.getCurrentThread()，value 是线程需要保存的变量。</li>
<li>ThreadLocal.set(value)相当map.put(Thread.getCurrentThread(), value)。</li>
<li>ThreadLocal.get() 相当map.get(Thread.getCurrentThread())。</li>
<li>内存问题 ： 在并发量高的时候，可能有内存溢出。</li>
<li>使用ThreadLocal的时候，一定注意回收资源问题，每个线程结束之前，将当前线程保存的线程变量一定要删除 ，调用ThreadLocal.remove()，要不会发生泄露。run方法的finally代码块。</li>
</ul>
<p>​        <em>在一个操作系统中，线程和进程是有数量上限的。在操作系统中，确定线程和进程唯一性的唯一条件就是线程或进程 ID。操作系统在回收线程或进程的时候，不是一定杀死线程或进程，在繁忙的时候，只会做情况线程或进程栈数据的操作，重复使用线程或进程。</em></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">static</span> String name = <span class="string">"zhangsan"</span>;</span><br><span class="line">    <span class="keyword">static</span> ThreadLocal&lt;String&gt; tl = <span class="keyword">new</span> ThreadLocal&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(name);    <span class="comment">// lisi</span></span><br><span class="line">                System.out.println(tl.get());    <span class="comment">// null</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                name = <span class="string">"lisi"</span>;</span><br><span class="line">                tl.set(<span class="string">"wangwu"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><em>小编是一枚Java Coder，业余写文章，现主营微信公众号《Java患者》，喜欢的话关注我的公众号或者加我微信我们一起学习Java</em></p>
<p><img src="\111公众号.jpg" alt=""></p>
<h2 id="元婴期（并发容器）"><a href="#元婴期（并发容器）" class="headerlink" title="元婴期（并发容器）"></a>元婴期（并发容器）</h2><p>​        <em>解决并发情况下的容器线程安全问题的。给多线程环境准备一个线程安全的容器对象。线程安全的容器对象： Vector, Hashtable。线程安全容器对象，都是使用 synchronized方法实现的。</em><br>​        <em>concurrent 包中的同步容器，大多数是使用系统底层技术实现的线程安全。类似 native。Java8 中使用 CAS。</em></p>
<h3 id="元婴前期（Map-Set）"><a href="#元婴前期（Map-Set）" class="headerlink" title="元婴前期（Map/Set）"></a>元婴前期（Map/Set）</h3><ul>
<li>ConcurrentHashMap/ConcurrentHashSet底层哈希实现的同步 Map(Set)。效率高，线程安全。使用系统底层技术实现线程安全。量级较 synchronized 低。key 和 value 不能为 null。</li>
<li>ConcurrentSkipListMap/ConcurrentSkipListSet底层跳表（SkipList）实现的同步 Map(Set)。有序，效率比 ConcurrentHashMap 稍低。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01_ConcurrentMap</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Map&lt;String, String&gt; map = <span class="keyword">new</span> Hashtable&lt;&gt;();    <span class="comment">// Collections.syncxxxxxx</span></span><br><span class="line">        <span class="comment">// final Map&lt;String, String&gt; map = new ConcurrentHashMap&lt;&gt;();</span></span><br><span class="line">        <span class="comment">// final Map&lt;String, String&gt; map = new ConcurrentSkipListMap&lt;&gt;();    数据结构跳表</span></span><br><span class="line">        <span class="keyword">final</span> Random r = <span class="keyword">new</span> Random();</span><br><span class="line">        Thread[] array = <span class="keyword">new</span> Thread[<span class="number">100</span>];</span><br><span class="line">        <span class="keyword">final</span> CountDownLatch latch = <span class="keyword">new</span> CountDownLatch(array.length);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">long</span> begin = System.currentTimeMillis();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; array.length; i++) &#123;</span><br><span class="line">            array[i] = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">10000</span>; j++) &#123;</span><br><span class="line">                        map.put(<span class="string">"key"</span> + r.nextInt(<span class="number">100000</span>), <span class="string">"value"</span> + r.nextInt(<span class="number">100000</span>));</span><br><span class="line">                    &#125;</span><br><span class="line">                    latch.countDown();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Thread t : array) &#123;</span><br><span class="line">            t.start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            latch.await();    <span class="comment">//等待门闩开放</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">long</span> end = System.currentTimeMillis();</span><br><span class="line">        System.out.println(<span class="string">"执行时间为 ： "</span> + (end - begin) + <span class="string">"毫秒！"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>调表机构：</strong>存10、18、15、20、19。</p>
<p><img src="\media\跳表.jpg" alt="跳表"></p>
<h3 id="元婴中期（List）"><a href="#元婴中期（List）" class="headerlink" title="元婴中期（List）"></a>元婴中期（List）</h3><ul>
<li>CopyOnWriteArrayList：写时复制集合，效率低，读取效率高。每次写入数据，都会创建一个新的底层数组。</li>
<li>浪费空间保证数据的安全。</li>
<li>初始容量1，每次新增的内容，创建容量+1。</li>
<li>取得时候，取最新的数组。remove最后一个数据，直接用上一个数组。</li>
<li>set和remove其他数据，重新创建数组。</li>
<li>存在幻读（写的时候，有读操作，不是最新添加的数据）</li>
<li>存在脏读（写的时候，有读操作，不是最新添加的数据）</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_02_CopyOnWriteList</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// final List&lt;String&gt; list = new ArrayList&lt;&gt;(); 线程不安全</span></span><br><span class="line">        <span class="comment">// final List&lt;String&gt; list = new Vector&lt;&gt;();    线程安全 更快</span></span><br><span class="line">        <span class="keyword">final</span> List&lt;String&gt; list = <span class="keyword">new</span> CopyOnWriteArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">final</span> Random r = <span class="keyword">new</span> Random();</span><br><span class="line">        Thread[] array = <span class="keyword">new</span> Thread[<span class="number">100</span>];</span><br><span class="line">        <span class="keyword">final</span> CountDownLatch latch = <span class="keyword">new</span> CountDownLatch(array.length);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">long</span> begin = System.currentTimeMillis();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; array.length; i++)&#123;</span><br><span class="line">            array[i] = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">1000</span>; j++)&#123;</span><br><span class="line">                        list.add(<span class="string">"value"</span> + r.nextInt(<span class="number">100000</span>));</span><br><span class="line">                    &#125;</span><br><span class="line">                    latch.countDown();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(Thread t : array)&#123;</span><br><span class="line">            t.start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            latch.await();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">long</span> end = System.currentTimeMillis();</span><br><span class="line">        System.out.println(<span class="string">"执行时间为 ： "</span> + (end-begin) + <span class="string">"毫秒！"</span>);</span><br><span class="line">        System.out.println(<span class="string">"List.size() : "</span> + list.size());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="元婴后期（Queue）"><a href="#元婴后期（Queue）" class="headerlink" title="元婴后期（Queue）"></a>元婴后期（Queue）</h3><p><strong>ConcurrentLinkedQueue：</strong>基础链表同步队列。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_03_ConcurrentLinkedQueue</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Queue&lt;String&gt; queue = <span class="keyword">new</span> ConcurrentLinkedQueue&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">            queue.offer(<span class="string">"value"</span> + i);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(queue);</span><br><span class="line">        System.out.println(queue.size());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// peek() -&gt; 查看queue中的首数据</span></span><br><span class="line">        System.out.println(queue.peek());</span><br><span class="line">        System.out.println(queue.size());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// poll() -&gt; 获取queue中的首数据</span></span><br><span class="line">        System.out.println(queue.poll());</span><br><span class="line">        System.out.println(queue.size());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>LinkedBlockingQueue：</strong>阻塞队列，队列容量不足自动阻塞，队列容量为 0 自动阻塞。</p>
<ul>
<li>put自动阻塞， 队列容量满后，自动阻塞。</li>
<li>take自动阻塞方法， 队列容量为0后，自动阻塞。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_04_LinkedBlockingQueue</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">final</span> BlockingQueue&lt;String&gt; queue = <span class="keyword">new</span> LinkedBlockingQueue&lt;&gt;();</span><br><span class="line">    <span class="keyword">final</span> Random r = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_04_LinkedBlockingQueue t = <span class="keyword">new</span> Test_04_LinkedBlockingQueue();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        t.queue.put(<span class="string">"value"</span>+t.r.nextInt(<span class="number">1000</span>));</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"producer"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            System.out.println(Thread.currentThread().getName() + </span><br><span class="line">                                    <span class="string">" - "</span> + t.queue.take());</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"consumer"</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ArrayBlockingQueue：</strong>底层数组实现的有界队列。自动阻塞。根据调用 API（add/put/offer）不同，有不同特性。当容量不足的时候，有阻塞能力。</p>
<ul>
<li>add 方法在容量不足的时候，抛出异常。</li>
<li>put 方法在容量不足的时候，阻塞等待。</li>
<li>offer 方法，<ul>
<li>单参数 offer 方法，不阻塞。容量不足的时候，返回 false。当前新增数据操作放弃。</li>
<li>三参数 offer 方法（offer(value,times,timeunit)），容量不足的时候，阻塞 times 时长（单<br>位为 timeunit），如果在阻塞时长内，有容量空闲，新增数据返回 true。如果阻塞时长范围<br>内，无容量空闲，放弃新增数据，返回 false。</li>
</ul>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_05_ArrayBlockingQueue</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">final</span> BlockingQueue&lt;String&gt; queue = <span class="keyword">new</span> ArrayBlockingQueue&lt;&gt;(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_05_ArrayBlockingQueue t = <span class="keyword">new</span> Test_05_ArrayBlockingQueue();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)&#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// System.out.println("add method : " + t.queue.add("value"+i));</span></span><br><span class="line">            ---------------------------------------------------------------------</span><br><span class="line">            <span class="comment">/*try &#123;</span></span><br><span class="line"><span class="comment">                t.queue.put("put"+i);</span></span><br><span class="line"><span class="comment">            &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">                e.printStackTrace();</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">            System.out.println("put method : " + i);*/</span></span><br><span class="line">            ---------------------------------------------------------------------</span><br><span class="line">            <span class="comment">// System.out.println("offer method : " + t.queue.offer("value"+i));</span></span><br><span class="line">            ---------------------------------------------------------------------</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">"offer method : "</span> + </span><br><span class="line">                            t.queue.offer(<span class="string">"value"</span>+i, <span class="number">1</span>, TimeUnit.SECONDS));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(t.queue);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>DelayQueue：</strong>延时队列。根据比较机制，实现自定义处理顺序的队列。常用于定时任务。</p>
<ul>
<li>通过比较方法，比较排列，获取。</li>
<li>可以保存的对象一定要实现Delayed接口。Delayed接口继承Comparable接口。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_06_DelayQueue</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> BlockingQueue&lt;MyTask_06&gt; queue = <span class="keyword">new</span> DelayQueue&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> value = System.currentTimeMillis();</span><br><span class="line">        MyTask_06 task1 = <span class="keyword">new</span> MyTask_06(value + <span class="number">2000</span>);</span><br><span class="line">        MyTask_06 task2 = <span class="keyword">new</span> MyTask_06(value + <span class="number">1000</span>);</span><br><span class="line">        MyTask_06 task3 = <span class="keyword">new</span> MyTask_06(value + <span class="number">3000</span>);</span><br><span class="line">        MyTask_06 task4 = <span class="keyword">new</span> MyTask_06(value + <span class="number">2500</span>);</span><br><span class="line">        MyTask_06 task5 = <span class="keyword">new</span> MyTask_06(value + <span class="number">1500</span>);</span><br><span class="line"></span><br><span class="line">        queue.put(task1);</span><br><span class="line">        queue.put(task2);</span><br><span class="line">        queue.put(task3);</span><br><span class="line">        queue.put(task4);</span><br><span class="line">        queue.put(task5);</span><br><span class="line"></span><br><span class="line">        System.out.println(queue);</span><br><span class="line">        System.out.println(value);</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)&#123;</span><br><span class="line">            System.out.println(queue.take());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyTask_06</span> <span class="keyword">implements</span> <span class="title">Delayed</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">long</span> compareValue;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyTask_06</span><span class="params">(<span class="keyword">long</span> compareValue)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.compareValue = compareValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 比较大小。自动实现升序</span></span><br><span class="line"><span class="comment">     * 建议和getDelay方法配合完成。</span></span><br><span class="line"><span class="comment">     * 如果在DelayQueue是需要按时间完成的计划任务，必须配合getDelay方法完成。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compareTo</span><span class="params">(Delayed o)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="keyword">int</span>)(<span class="keyword">this</span>.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取计划时长的方法。</span></span><br><span class="line"><span class="comment">     * 根据参数TimeUnit来决定，如何返回结果值。秒，毫秒</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">getDelay</span><span class="params">(TimeUnit unit)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> unit.convert(compareValue - System.currentTimeMillis(), TimeUnit.MILLISECONDS);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Task compare value is : "</span> + <span class="keyword">this</span>.compareValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>LinkedTransferQueue：</strong>转移队列，</p>
<ul>
<li>使用 transfer 方法，没有消费者，就阻塞。必须有消费者（take()方法的调用者），实现数据的即时处理（电话）。</li>
<li>无容量的，放数组，容量为零，这时候要阻塞。等另一个线程来拿，不经过容器的存储来转移数组。</li>
<li>使用 add方法，直接存在容器中。队列会保存数据，不做阻塞等待（短信）。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_07_TransferQueue</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    TransferQueue&lt;String&gt; queue = <span class="keyword">new</span> LinkedTransferQueue&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_07_TransferQueue t = <span class="keyword">new</span> Test_07_TransferQueue();<span class="comment">//为了匿名内部累方法中获得queue引用。</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/*new Thread(new Runnable() &#123;</span></span><br><span class="line"><span class="comment">            @Override</span></span><br><span class="line"><span class="comment">            public void run() &#123;</span></span><br><span class="line"><span class="comment">                try &#123;</span></span><br><span class="line"><span class="comment">                    System.out.println(Thread.currentThread().getName() + " thread begin " );</span></span><br><span class="line"><span class="comment">                    System.out.println(Thread.currentThread().getName() + " - " + t.queue.take());</span></span><br><span class="line"><span class="comment">                &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">                    e.printStackTrace();</span></span><br><span class="line"><span class="comment">                &#125;</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">        &#125;, "output thread").start();</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        try &#123;</span></span><br><span class="line"><span class="comment">            TimeUnit.SECONDS.sleep(2);</span></span><br><span class="line"><span class="comment">        &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">            e.printStackTrace();</span></span><br><span class="line"><span class="comment">        &#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        try &#123;</span></span><br><span class="line"><span class="comment">            t.queue.transfer("test string");</span></span><br><span class="line"><span class="comment">        &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">            e.printStackTrace();</span></span><br><span class="line"><span class="comment">        &#125;*/</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    t.queue.transfer(<span class="string">"test string"</span>);</span><br><span class="line">                    <span class="comment">// t.queue.add("test string");</span></span><br><span class="line">                    System.out.println(<span class="string">"add ok"</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" thread begin "</span> );</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" - "</span> + t.queue.take());</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"output thread"</span>).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>SynchronusQueue：</strong>同步队列，是一个容量为 0 的队列。是一个特殊的 TransferQueue。</p>
<ul>
<li>必须现有消费线程等待，才能使用的队列。</li>
<li>add 方法，无阻塞。若没有消费线程阻塞等待数据，则抛出非阻塞异常。</li>
<li>put 方法，有阻塞。若没有消费线程阻塞等待数据，则阻塞。</li>
<li>场景：玩家与玩家之间的匹配。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_08_SynchronusQueue</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    BlockingQueue&lt;String&gt; queue = <span class="keyword">new</span> SynchronousQueue&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Test_08_SynchronusQueue t = <span class="keyword">new</span> Test_08_SynchronusQueue();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" thread begin "</span> );</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" - "</span> + t.queue.take());</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"output thread"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*try &#123;</span></span><br><span class="line"><span class="comment">            TimeUnit.SECONDS.sleep(3);</span></span><br><span class="line"><span class="comment">        &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">            e.printStackTrace();</span></span><br><span class="line"><span class="comment">        &#125;*/</span></span><br><span class="line">        <span class="comment">// t.queue.add("test add");</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            t.queue.put(<span class="string">"test put"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">" queue size : "</span> + t.queue.size());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="元婴圆满（线程池）"><a href="#元婴圆满（线程池）" class="headerlink" title="元婴圆满（线程池）"></a>元婴圆满（线程池）</h3><p>​        <strong>Executor：</strong>线程池顶级接口。定义方法，void execute(Runnable)。方法是用于处理任务的一个服务方法。调用者提供 Runnable 接口的实现，线程池通过线程执行这个 Runnable。服务方法无返回值的。是 Runnable 接口中的 run 方法无返回值。常用方法 - void execute(Runnable)，作用是启动线程任务的。</p>
<p>​        他不是线程池，他是线程池线程池底层处理机制。在使用线程池的时候，底层如何处理本线程的逻辑。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01_MyExecutor</span> <span class="keyword">implements</span> <span class="title">Executor</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Test_01_MyExecutor().execute(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">" - test executor"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(Runnable command)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Thread(command).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ExecutorService：</strong>Executor 接口的子接口。提供了一个新的服务方法，submit。有返回值（Future 类型）。submit 方法提供了 overload 方法。其中有参数类型为 Runnable 的，不需要提供返回值的；有参数类型为 Callable，可以提供线程执行后的返回值。</p>
<ul>
<li><p>他是线程池服务类型。所有的线程池类型都实现这个接口，实现这个接口，代表可以提供线程池能力。</p>
</li>
<li><p>Future是 submit 方法的返回值。代表未来，也就是线程执行结束后的一种结果。如返回值。</p>
</li>
<li><p>常见方法</p>
<ul>
<li>void execute(Runnable)</li>
<li>Future submit(Callable)</li>
<li>Future submit(Runnable)</li>
<li>shutdown()：优雅关闭。 不是强行关闭线程池，回收线程池中的资源。而是不再处理新的任务，将已接收的任务处理完毕后再关闭。</li>
</ul>
</li>
<li><p>线程池状态</p>
<ul>
<li>Running - 线程池正在执行中。活动状态。</li>
<li>ShuttingDown - 线程池正在关闭过程中。优雅关闭。一旦进入这个状态，线程池不再接收新的任务，处理所有已接收的任务，处理完毕后，关闭线程池。不能执行submit方法和execute方法。</li>
<li>Terminated - 线程池已经关闭。不能执行submit方法和execute方法。</li>
</ul>
</li>
</ul>
<hr>
<p><strong>Future：</strong>未来结果，代表线程任务执行结束后的结果。获取线程执行结果的方式是通过 get 方法获取的。</p>
<ul>
<li>get 无参，阻塞等待线程执行结束，并得到结果。</li>
<li>get 有参，阻塞固定时长，等待线程执行结束后的结果，如果在阻塞时长范围内，线程未执行结束，抛出异常。</li>
<li>常用方法：<ul>
<li>T get() </li>
<li>T get(long, TimeUnit)</li>
</ul>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_03_Future</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span>&#123;</span><br><span class="line">        <span class="comment">/*FutureTask&lt;String&gt; task = new FutureTask&lt;&gt;(new Callable&lt;String&gt;() &#123;</span></span><br><span class="line"><span class="comment">            @Override</span></span><br><span class="line"><span class="comment">            public String call() throws Exception &#123;</span></span><br><span class="line"><span class="comment">                return "first future task";</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">        &#125;);</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        new Thread(task).start();</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        System.out.println(task.get());*/</span></span><br><span class="line">        <span class="comment">// 上面代码和下面一模一样的</span></span><br><span class="line">        ExecutorService service = Executors.newFixedThreadPool(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">        Future&lt;String&gt; future = service.submit(<span class="keyword">new</span> Callable&lt;String&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> String <span class="title">call</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(<span class="string">"aaa"</span>);</span><br><span class="line">                <span class="keyword">return</span> Thread.currentThread().getName() + <span class="string">" - test executor"</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        System.out.println(future);</span><br><span class="line">        System.out.println(future.isDone()); <span class="comment">// 查看线程是否结束， 任务是否完成。 call方法是否执行结束</span></span><br><span class="line"></span><br><span class="line">        System.out.println(future.get()); <span class="comment">// 获取call方法的返回值。</span></span><br><span class="line">        System.out.println(future.isDone());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<hr>
<p><strong>Callable：</strong>可执行接口， 类似 Runnable 接口，也是可以启动一个线程的接口。其中定义的方法是<br>call，call 方法的作用和 Runnable 中的 run 方法完全一致，call 方法有返回值。</p>
<ul>
<li>接口方法 ： Object call();相当于 Runnable 接口中的 run 方法。区别为此方法有返回值。<br>不能抛出已检查异常。</li>
<li>和 Runnable 接口的选择 - 需要返回值或需要抛出异常时，使用 Callable，其他情况可<br>任意选择。</li>
</ul>
<hr>
<p><strong>Executors：</strong>工具类型，为 Executor 线程池提供工具方法。</p>
<ul>
<li>可以快速的提供若干种线程池。如：固定容量的，无限容量的，容量为 1 等各种线程池。</li>
<li>线程池是一个进程级的重量级资源。默认的生命周期和 JVM 一致。当开启线程池后，直到 JVM 关闭为止，是线程池的默认生命周期。如果手工调用 shutdown 方法，那么线程池执行所有的任务后，自动关闭。不调用shutdown方法，程序一直不关闭的。</li>
<li>开始 - 创建线程池。</li>
<li>结束 - JVM 关闭或调用 shutdown 并处理完所有的任务。</li>
<li>类似 Arrays，Collections 等工具类型的功用。</li>
</ul>
<hr>
<p><strong>FixedThreadPool：</strong>容量固定的线程池。活动状态和线程池容量是有上限的线程池。</p>
<ul>
<li><p>所有的线程池中，都有一个任务队列。使用的是 BlockingQueue<runnable>作为任务的载体。当任务数量大于线程池容量的时候，没有运行的任务保存在任务队列中，当线程有空闲的，自动从队列中取出任务执行。</runnable></p>
</li>
<li><p>使用场景： 大多数情况下，使用的线程池，首选推荐 FixedThreadPool。OS 系统和硬件是有线程支持上限。不能随意的无限制提供线程池。</p>
</li>
<li><p>线程池默认的容量上限是 Integer.MAX_VALUE。</p>
</li>
<li><p>常见的线程池容量： PC - 200。 服务器 - 1000~10000</p>
</li>
<li><p>queued tasks - 任务队列，completed tasks - 结束任务队列</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_02_FixedThreadPool</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService service =</span><br><span class="line">                Executors.newFixedThreadPool(<span class="number">5</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++) &#123;</span><br><span class="line">            service.execute(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" - test executor"</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks             = 0]</span></span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">        service.shutdown();</span><br><span class="line">        <span class="comment">// 是否已经结束， 相当于回收了资源。</span></span><br><span class="line">        System.out.println(service.isTerminated()); <span class="comment">// false</span></span><br><span class="line">        <span class="comment">// 是否已经关闭， 是否调用过shutdown方法</span></span><br><span class="line">        System.out.println(service.isShutdown());   <span class="comment">//true</span></span><br><span class="line">        <span class="comment">// [Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed               tasks = 0]</span></span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// service.shutdown();</span></span><br><span class="line">        System.out.println(service.isTerminated()); <span class="comment">//true</span></span><br><span class="line">        System.out.println(service.isShutdown());   <span class="comment">//true</span></span><br><span class="line">        <span class="comment">// [Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed                 tasks = 6]</span></span><br><span class="line">        System.out.println(service);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>​        <strong>CachedThreadPool：</strong>缓存的线程池。容量不限（Integer.MAX_VALUE）。自动扩容。容量管理策略：如果线程池中的线程数量不满足任务执行，创建新的线程。每次有新任务无法即时处理的时候，都会创建新的线程。</p>
<ul>
<li>当线程池中的线程空闲时长达到一定的临界值（默认 60 秒），自动释放线程。</li>
<li>默认线程空闲 60 秒，自动销毁。</li>
<li>应用场景： 内部应用或测试应用。 内部应用，有条件的内部数据瞬间处理时应用，如：电信平台夜间执行数据整理（有把握在短时间内处理完所有工作，且对硬件和软件有足够的信心）。 </li>
<li>测试应用，在测试的时候，尝试得到硬件或软件的最高负载量，用于提供FixedThreadPool 容量的指导。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_05_CachedThreadPool</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService service = Executors.newCachedThreadPool();</span><br><span class="line">        System.out.println(service);    <span class="comment">// 容量为0</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)&#123;</span><br><span class="line">            service.execute(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" - test executor"</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(service);    <span class="comment">// 容量为5</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">65</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(service);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ScheduledThreadPool：</strong>计划任务线程池。可以根据计划自动执行任务的线程池。</p>
<ul>
<li>scheduleAtFixedRate(Runnable, start_limit, limit, timeunit)<ul>
<li>runnable - 要执行的任务。</li>
<li>start_limit - 第一次任务执行的间隔。</li>
<li>limit - 多次任务执行的间隔。</li>
<li>timeunit - 多次任务执行间隔的时间单位。</li>
</ul>
</li>
<li>他是阻塞的，效率低下。</li>
<li>他本质就是DelayedQueue</li>
<li>每间隔一定的时间，随机一个线程运行，并且运行完的线程，不会销毁，会继续等待下次选中运行。</li>
<li>使用场景： 计划任务时选用（具体与DelaydQueue比较后选择），如：电信行业中的数据整理，每分钟整理，每消失整理，每天整理等.</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_07_ScheduledThreadPool</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ScheduledExecutorService service = Executors.newScheduledThreadPool(<span class="number">3</span>);</span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 定时完成任务。 scheduleAtFixedRate(Runnable, start_limit, limit, timeunit)</span></span><br><span class="line">        <span class="comment">// runnable - 要执行的任务。</span></span><br><span class="line">        service.scheduleAtFixedRate(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(Thread.currentThread().getName());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="number">0</span>, <span class="number">300</span>, TimeUnit.MILLISECONDS);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>SingleThreadExceutor：</strong>单一容量的线程池。使用场景： 所有任务交给它处理，保证任务顺序时使用。如： 游戏大厅中的公共频道聊天。秒杀。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_06_SingleThreadExecutor</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService service = Executors.newSingleThreadExecutor();</span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)&#123;</span><br><span class="line">            service.execute(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" - test executor"</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ForkJoinPool：</strong>分支合并线程池（mapduce 类似的设计思想，递归思想的运用）。适合用于处理复杂任务。</p>
<ul>
<li>初始化线程容量与 CPU 核心数相关。</li>
<li>线程池中运行的内容必须是 ForkJoinTask 的子类型（RecursiveTask,RecursiveAction）。</li>
<li>ForkJoinPool - 分支合并线程池。 可以递归完成复杂任务。要求可分支合并的任务必须是 ForkJoinTask 类型的子类型。其中提供了分支和合并的能力。ForkJoinTask 类型提供了两个抽象子类型，RecursiveTask 有返回结果的分支合并任务,RecursiveAction 无返回结果的分支合并任务。（Callable/Runnable）compute 方法：就是任务的执行逻辑。</li>
<li>ForkJoinPool 没有所谓的容量。默认都是 1 个线程。根据任务自动的分支新的子线程。当子线程任务结束后，自动合并。所谓自动是根据 fork 和 join 两个方法实现的。</li>
<li>应用： 主要是做科学计算或天文计算的。数据分析的.</li>
<li>拿空间换时间，效率高，但要看CPU能力。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_08_ForkJoinPool</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span>[] numbers = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">1000000</span>];</span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_SIZE = <span class="number">50000</span>;</span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">static</span> Random r = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; numbers.length; i++)&#123;</span><br><span class="line">            numbers[i] = r.nextInt(<span class="number">1000</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">AddTask</span> <span class="keyword">extends</span> <span class="title">RecursiveTask</span>&lt;<span class="title">Long</span>&gt;</span>&#123; <span class="comment">// RecursiveAction</span></span><br><span class="line">        <span class="keyword">int</span> begin, end;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">AddTask</span><span class="params">(<span class="keyword">int</span> begin, <span class="keyword">int</span> end)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.begin = begin;</span><br><span class="line">            <span class="keyword">this</span>.end = end;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// </span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> Long <span class="title">compute</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span>((end - begin) &lt; MAX_SIZE)&#123;</span><br><span class="line">                <span class="keyword">long</span> sum = <span class="number">0L</span>;</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> i = begin; i &lt; end; i++)&#123;</span><br><span class="line">                    sum += numbers[i];</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// System.out.println("form " + begin + " to " + end + " sum is : " + sum);</span></span><br><span class="line">                <span class="keyword">return</span> sum;</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                <span class="keyword">int</span> middle = begin + (end - begin)/<span class="number">2</span>;</span><br><span class="line">                AddTask task1 = <span class="keyword">new</span> AddTask(begin, middle);</span><br><span class="line">                AddTask task2 = <span class="keyword">new</span> AddTask(middle, end);</span><br><span class="line">                task1.fork();<span class="comment">// 就是用于开启新的任务的。 就是分支工作的。 就是开启一个新的线程任务。</span></span><br><span class="line">                task2.fork();</span><br><span class="line">                <span class="comment">// join - 合并。将任务的结果获取。 这是一个阻塞方法。一定会得到结果数据。</span></span><br><span class="line">                <span class="keyword">return</span> task1.join() + task2.join();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException, ExecutionException, IOException </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> result = <span class="number">0L</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; numbers.length; i++)&#123;</span><br><span class="line">            result += numbers[i];</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(result);</span><br><span class="line"></span><br><span class="line">        ForkJoinPool pool = <span class="keyword">new</span> ForkJoinPool();</span><br><span class="line">        AddTask task = <span class="keyword">new</span> AddTask(<span class="number">0</span>, numbers.length);</span><br><span class="line"></span><br><span class="line">        Future&lt;Long&gt; future = pool.submit(task);</span><br><span class="line">        System.out.println(future.get());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ThreadPoolExecutor：</strong>线程池底层实现。除 ForkJoinPool 外，其他常用线程池底层都是使用ThreadPoolExecutor实现的。public ThreadPoolExecutor(int corePoolSize，int maximumPoolSize，long keepAliveTime，TimeUnit unit，BlockingQueue<runnable> workQueue);</runnable></p>
<ul>
<li>corePoolSize： 核心容量，创建线程池的时候，默认有多少线程。也是线程池保持的最少线程数</li>
<li>maximumPoolSize： 最大容量，线程池最多有多少线程</li>
<li>keepAliveTime：生命周期，0 为永久。当线程空闲多久后，自动回收。</li>
<li>unit：生命周期单位，为生命周期提供单位，如：秒，毫秒</li>
<li>workQueue：任务队列，阻塞队列。注意，泛型必须是</li>
</ul>
<p>使用场景： 默认提供的线程池不满足条件时使用。如：初始线程数据 4，最大线程数200，线程空闲周期 30 秒。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_09_ThreadPoolExecutor</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 模拟fixedThreadPool， 核心线程5个，最大容量5个，线程的生命周期无限。</span></span><br><span class="line">        ExecutorService service = </span><br><span class="line">                <span class="keyword">new</span> ThreadPoolExecutor(<span class="number">5</span>, <span class="number">5</span>, <span class="number">0L</span>, TimeUnit.MILLISECONDS, </span><br><span class="line">                        <span class="keyword">new</span> LinkedBlockingQueue&lt;Runnable&gt;());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++)&#123;</span><br><span class="line">            service.execute(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">" - test executor"</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">        service.shutdown();</span><br><span class="line">        System.out.println(service.isTerminated());</span><br><span class="line">        System.out.println(service.isShutdown());</span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        service.shutdown();</span><br><span class="line">        System.out.println(service.isTerminated());</span><br><span class="line">        System.out.println(service.isShutdown());</span><br><span class="line">        System.out.println(service);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<hr>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">练习：</span><br><span class="line">启动若干线程，并行访问同一个容器中的数据。保证获取容器中数据时没有数据错误，且线程安全。</span><br><span class="line">如：售票，秒杀等业务。</span><br></pre></td></tr></table></figure>
<p>使用synchronized</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_01</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> List&lt;String&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    <span class="comment">// static List&lt;String&gt; list = new Vector&lt;&gt;();</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10000</span>; i++)&#123;</span><br><span class="line">            list.add(<span class="string">"String "</span> + i);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">while</span>(list.size() &gt; <span class="number">0</span>)&#123;</span><br><span class="line">                        System.out.println(Thread.currentThread().getName() + <span class="string">" - "</span> + list.remove(<span class="number">0</span>));</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"Thread"</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*for(int i = 0; i &lt; 10; i++)&#123;</span></span><br><span class="line"><span class="comment">            new Thread(new Runnable() &#123;</span></span><br><span class="line"><span class="comment">                @Override</span></span><br><span class="line"><span class="comment">                public void run() &#123;</span></span><br><span class="line"><span class="comment">                    while(true)&#123;</span></span><br><span class="line"><span class="comment">                        synchronized (list) &#123;</span></span><br><span class="line"><span class="comment">                            if(list.size() &lt;= 0)&#123;</span></span><br><span class="line"><span class="comment">                                break;</span></span><br><span class="line"><span class="comment">                            &#125;</span></span><br><span class="line"><span class="comment">                            System.out.println(Thread.currentThread().getName() + " - " + list.remove(0));</span></span><br><span class="line"><span class="comment">                        &#125;</span></span><br><span class="line"><span class="comment">                    &#125;</span></span><br><span class="line"><span class="comment">                &#125;</span></span><br><span class="line"><span class="comment">            &#125;, "Thread" + i).start();</span></span><br><span class="line"><span class="comment">        &#125;*/</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>使用queue</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">public class Test_02 &#123;</span><br><span class="line"></span><br><span class="line">    static Queue&lt;String&gt; list = new ConcurrentLinkedQueue&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    static&#123;</span><br><span class="line">        for(int i = 0; i &lt; 10000; i++)&#123;</span><br><span class="line">            list.add(&quot;String &quot; + i);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        for(int i = 0; i &lt; 10; i++)&#123;</span><br><span class="line">            new Thread(new Runnable() &#123;</span><br><span class="line">                @Override</span><br><span class="line">                public void run() &#123;</span><br><span class="line">                    while(true)&#123;</span><br><span class="line">                        String str = list.poll();</span><br><span class="line">                        if(str == null)&#123;</span><br><span class="line">                            break;</span><br><span class="line">                        &#125;</span><br><span class="line">                        System.out.println(Thread.currentThread().getName() + &quot; - &quot; + str);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, &quot;Thread&quot; + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><em>小编是一枚Java Coder，业余写文章，现主营微信公众号《Java患者》，喜欢的话关注我的公众号或者加我微信我们一起学习Java</em></p>
<p><img src="\111公众号.jpg" alt=""></p>
<h2 id="化神期（JVM1-7）"><a href="#化神期（JVM1-7）" class="headerlink" title="化神期（JVM1.7）"></a>化神期（JVM1.7）</h2><h3 id="化神前期（jvm结构）"><a href="#化神前期（jvm结构）" class="headerlink" title="化神前期（jvm结构）"></a>化神前期（jvm结构）</h3><p><strong>jvm基本结构图：</strong></p>
<p><img src="\media\jvm基本结构图.jpg" alt="jvm基本结构图"></p>
<ul>
<li><strong>类加载子系统：</strong>类加载子系统负责从文件系统或者网络中加载 Class 信息，如ClassLoad这里面的组件。</li>
<li><strong>方法区：</strong>加载的类信息存放于一块称为方法区的内存空间。除了类的信息外，方法区中可能还会存放运行时常量池信息，包括字符串字面量和数字常量（这部分常量信息是 Class 文件中常量池部分的内存映射）。</li>
<li><strong>Java 堆：</strong>java 堆在虚拟机启动的时候建立，它是 java 程序最主要的内存工作区域。几乎所有的java 对象实例都存放在 java 堆中。堆空间是所有线程共享的，这是一块与 java 应用密切相关的内存空间。</li>
<li><strong>直接内存：</strong>java 的 NIO 库允许 java 程序使用直接内存。直接内存是在 java 堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于 java 堆。因此出于性能的考虑，读写频繁的场合可能会考虑使用直接内存。由于直接内存在 java 堆外，因此它的大小不会直接受限于 Xmx 指定的最大堆大小，但是系统内存是有限的，java 堆和直接内存的总和依然受限于操作系统能给出的最大内存。</li>
<li><strong>垃圾回收系统：</strong>垃圾回收系统是 java 虚拟机的重要组成部分，垃圾回收器可以对方法区、java 堆和直接内存进行回收。其中，java 堆是垃圾收集器的工作重点。和 C/C++不同，java 中所有的对象空间释放都是隐式的，也就是说，java 中没有类似 free()或者 delete()这样的函数释放指定的内存区域。对于不再使用的垃圾对象，垃圾回收系统会在后台默默工作，默默查找、标识并释放垃圾对象，完成包括 java 堆、方法区和直接内存中的全自动化管理。</li>
<li><strong>Java 栈：</strong>每一个 java 虚拟机线程都有一个私有的 java 栈，一个线程的 java 栈在线程创建的时候被创建，java 栈中保存着帧信息，java 栈中保存着局部变量、方法参数，同时和 java 方法的调用、返回密切相关。</li>
<li><strong>本地方法栈：</strong>本地方法栈和 java 栈非常类似，最大的不同在于 java 栈用于方法的调用，而本地方法栈则用于本地方法的调用，作为对 java 虚拟机的重要扩展，java 虚拟机允许 java 直接调用本地方法（通常使用 C 编写）。</li>
<li><strong>PC 寄存器：</strong>PC（Program Counter）寄存器也是每一个线程私有的空间，java 虚拟机会为每一个 java线程创建 PC 寄存器。在任意时刻，一个 java 线程总是在执行一个方法，这个正在被执行的方法称为当前方法。如果当前方法不是本地方法，PC 寄存器就会指向当前正在被执行的指令。如果当前方法是本地方法，那么 PC 寄存器的值就是 undefined。</li>
<li><strong>Java HotSpot Client 模式和 Server 模式的区别：</strong>当虚拟机运行在-client 模式的时候,使用的是一个代号为 C1 的轻量级编译器, 而-server模式启动的虚拟机采用相对重量级,代号为 C2 的编译器. C2 比 C1 编译器编译的相对彻底,服务起来之后,性能更高。<ul>
<li>JDK 安装目录/jre/lib/（x86、i386、amd32、amd64）/jvm.cfg文件中的内容，-server 和-client 哪一个配置在上，执行引擎就是哪一个。如果是 JDK1.5版本且是 64 位系统应用时，-client 无效。</li>
<li>–64 位系统内容<br>-server KNOWN<br>-client IGNORE</li>
<li>–32 位系统内容<br>-server KNOWN<br>-client KNOWN</li>
<li>注意 ：在部分 JDK1.6 版本和后续的 JDK 版本 (64 位系统 ) 中， -client 参数已经不起作用<br>了， Server 模式成为唯一。</li>
</ul>
</li>
</ul>
<h3 id="化神中期（堆结构及对象分代）"><a href="#化神中期（堆结构及对象分代）" class="headerlink" title="化神中期（堆结构及对象分代）"></a>化神中期（堆结构及对象分代）</h3><ul>
<li><strong>什么是分代，分代的必要性是什么？</strong></li>
</ul>
<blockquote>
<p>​        Java 虚拟机根据对象存活的周期不同，把堆内存划分为几块，一般分为新生代、老年代和永久代（对 HotSpot 虚拟机而言），这就是 JVM 的内存分代策略。<br>​        堆内存是虚拟机管理的内存中最大的一块，也是垃圾回收最频繁的一块区域，我们程序所有的对象实例都存放在堆内存中。给堆内存分代是为了提高对象内存分配和垃圾回收的效率。试想一下，如果堆内存没有区域划分，所有的新创建的对象和生命周期很长的对象放在一起，随着程序的执行，堆内存需要频繁进行垃圾收集，而每次回收都要遍历所有的对象，遍历这些对象所花费的时间代价是巨大的，会严重影响我们的 GC 效率，并且会产生碎片。<br>​        有了内存分代，情况就不同了，新创建的对象会在新生代中分配内存，经过多次回收仍然存活下来的对象存放在老年代中，静态属性、类信息等存放在永久代中，新生代中的对象存活时间短，只需要在新生代区域中频繁进行 GC，老年代中对象生命周期长，内存回收的频率相对较低，不需要频繁进行回收，永久代中回收效果太差，一般不进行垃圾回收，还可以根据不同年代的特点采用合适的垃圾收集算法。分代收集大大提升了收集效率，这些都是内存分代带来的好处。</p>
</blockquote>
<ul>
<li><strong>分代的划分Java</strong> </li>
</ul>
<blockquote>
<p>​        虚拟机将堆内存划分为 新生代、老年代和永久代 ，永久代是 HotSpot 虚拟机特有的概念（JDK1.8 之后为 metaspace 替代永久代），它采用永久代的方式来实现方法区，其他的虚拟机实现没有这一概念，而且 HotSpot 也有取消永久代的趋势，在 JDK 1.7 中 HotSpot 已经开始了“去永久化”，把原本放在永久代的字符串常量池移出。永久主要存放常量、类信息、静态变量等数据，与垃圾回收关系不大，新生代和老年代是垃圾回收的主要区域。</p>
</blockquote>
<p><img src="\media\堆内存简图.jpg" alt="堆内存简图"></p>
<ul>
<li><strong>新生代（Young Generation)</strong></li>
</ul>
<blockquote>
<p>​        新生成的对象优先存放在新生代中，新生代对象朝生夕死，存活率很低，在新生代Eden中，常规应用进行一次垃圾收集一般可以回收 70% ~ 95% 的空间，回收效率很高。<br>​        HotSpot 将新生代划分为三块，一块较大的 Eden（伊甸）空间和两块较小的 Survivor（幸存者）空间，默认比例为 8：1：1。划分的目的是因为 HotSpot 采用复制算法来回收新生代，设置这个比例是为了充分利用内存空间，减少浪费。新生成的对象在 Eden 区分配（大对象除外，大对象直接进入老年代），当 Eden 区没有足够的空间进行分配时，虚拟机将发起一次Minor GC。<br>​        GC 开始时，对象只会存在于 Eden 区和 From Survivor 区，To Survivor 区是空的（作为保留区域）。GC 进行时，Eden 区中所有存活的对象都会被复制到 To Survivor 区，而在 FromSurvivor 区中，仍存活的对象会根据它们的年龄值决定去向，年龄值达到年龄阀值（默认为15，新生代中的对象每熬过一轮垃圾回收，年龄值就加 1，GC 分代年龄存储在对象的 header中）的对象会被移到老年代中，没有达到阀值的对象会被复制到 To Survivor 区。接着清空Eden 区和 From Survivor 区，新生代中存活的对象都在 To Survivor 区。接着， From Survivor区和 To Survivor 区会交换它们的角色（复制算法减少碎片），也就是新的 To Survivor 区就是上次 GC 清空的 FromSurvivor 区，新的 From Survivor 区就是上次 GC 的 To Survivor 区，总之，不管怎样都会保证To Survivor 区在一轮 GC 后是空的。GC 时当 To Survivor 区没有足够的空间存放上一次新生代收集下来的存活对象时，需要依赖老年代进行分配担保，将这些对象存放在老年代中。</p>
</blockquote>
<ul>
<li><strong>老年代（Old Generationn ）</strong></li>
</ul>
<blockquote>
<p>​        在新生代中经历了多次（具体看虚拟机配置的阀值）GC 后仍然存活下来的对象会进入老年代中。老年代中的对象生命周期较长，存活率比较高，在老年代中进行 GC 的频率相对而言较低，而且回收的速度也比较慢。</p>
</blockquote>
<ul>
<li><strong>永久代（Permanent Generationn）</strong></li>
</ul>
<blockquote>
<p>​        永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据，对这一区域而言，Java 虚拟机规范指出可以不进行垃圾收集，一般而言不会进行垃圾回收。</p>
</blockquote>
<h3 id="化神后期（垃圾回收算法及分代垃圾）"><a href="#化神后期（垃圾回收算法及分代垃圾）" class="headerlink" title="化神后期（垃圾回收算法及分代垃圾）"></a>化神后期（垃圾回收算法及分代垃圾）</h3><p> <strong>常见 垃圾回收算法</strong></p>
<ul>
<li>引用计数 （Reference Counting ）：比较古老的回收算法。原理是此对象有一个引用，即增加一个计数，删除一个引用则减少一个计数。垃圾回收时，只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题。</li>
<li>复制（Copying）：此算法把内存空间划为两个相等的区域，每次只使用其中一个区域。垃圾回收时，遍历当前使用区域，把正在使用中的对象复制到另外一个区域中。此算法每次只处理正在使用中的对象，因此复制成本比较小，同时复制过去以后还能进行相应的内存整理，不会出现“碎片”问题。当然，此算法的缺点也是很明显的，就是需要两倍内存空间。简图如下：</li>
</ul>
<p><img src="\media\复制算法.jpg" alt="复制算法"></p>
<ul>
<li>标记- 清除（Mark-Sweep ）：最古老的算法，此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象，第二阶段遍历整个堆，把未标记的对象清除。此算法需要<strong>暂停整个应用</strong>，同时，会产生内存碎片。简图如下：</li>
</ul>
<p><img src="\media\标记-清楚算法.jpg" alt="标记-清楚算法"></p>
<ul>
<li>标记- 整理（Mark-Compact ）：此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段，第一阶段从根节点开始标记所有被引用对象，第二阶段遍历整个堆，把清除未标记对象并且把存活对象“压缩”到堆的其中一块，按顺序排放。此算法避免了“标记-清除”的碎片问题，同时也避免了“复制”算法的空间问题。简图如下：</li>
</ul>
<p><img src="\media\标记-整理.jpg" alt="标记-整理"></p>
<p><strong>垃圾收集器的分类</strong></p>
<ul>
<li><p>次收集器：Scavenge GC，指发生在新生代的 GC，因为新生代的 Java 对象大多都是朝生夕死，所以<br>Scavenge GC 非常频繁，一般回收速度也比较快。</p>
<ul>
<li>当 Eden 空间不足以为对象分配内存时，会触发 Scavenge GC。</li>
<li>一般情况下，当新对象生成，并且在 Eden 申请空间失败时，就会触发 Scavenge GC，对Eden 区域进行 GC，清除非存活对象，并且把尚且存活的对象移动到 Survivor 区。然后整理Survivor 的两个区。这种方式的 GC 是对年轻代的 Eden 区进行，不会影响到年老代。因为大部分对象都是从 Eden 区开始的，同时 Eden 区不会分配的很大，所以 Eden 区的 GC 会频繁进行。因而，一般在这里需要使用速度快、效率高的算法，使 Eden 去能尽快空闲出来。</li>
<li>当年轻代堆空间紧张时会被触发</li>
<li>相对于全收集而言，收集间隔较短</li>
</ul>
</li>
<li><p>全收集器：Full GC，指发生在老年代的 GC，出现了 Full GC 一般会伴随着至少一次的 Minor GC（老年代的对象大部分是 Scavenge GC 过程中从新生代进入老年代），比如：分配担保失败。FullGC 的速度一般会比 Scavenge GC 慢 10 倍以上。</p>
<ul>
<li>当老年代内存不足或者显式调用 System.gc()方法时，会触发 Full GC。</li>
<li>当老年代或者持久代堆空间满了，会触发全收集操作。</li>
<li>可以使用 System.gc()方法来显式的启动全收集，全收集一般根据堆大小的不同，需要的时间不尽相同，但一般会比较长。</li>
</ul>
</li>
<li><p>垃圾回收器的常规组合使用：</p>
<ul>
<li>Serial、ParNew、Parallel Scabenage构成新生代回收器。</li>
<li>Serial Old、Parallel Old、CMS是老年代回收器。</li>
<li>G1新老通用</li>
</ul>
</li>
</ul>
<p><img src="\media\垃圾回收的常见匹配.jpg" alt="垃圾回收的常见匹配"></p>
<p><strong>分代垃圾收集器</strong></p>
<ul>
<li>串行收集器（Serial ）：JDK1.3之前JVM唯一一个次收集器（新生代收集器），1.5版本也是默认次收集器，它是串收集器。<ul>
<li>Serial 收集器是 Hotspot 运行在 Client 模式下的默认新生代收集器。</li>
<li>它的特点是：只用一个 CPU（计算核心）/一条线程去完成 GC 工作, 且在进行垃圾收集时必须暂停其他所有的工作线程(“Stop The World” -后面简称 STW)。</li>
<li>可以使用-XX:+UseSerialGC 打开。虽然是单线程收集, 但它却简单而高效, 在 VM 管理内存不大的情况下(收集几十 M~一两百 M 的新生代), 停顿时间完全可以控制在几十毫秒~一百多毫秒内。</li>
<li>大多数收集器都是在串行收集器进行优化，减少他停顿的时间。</li>
</ul>
</li>
</ul>
<p><img src="\media\串行收集器.jpg" alt=""></p>
<ul>
<li><p>并行收集器（ParNew ）：ParNew 收集器其实是前面 Serial 的多线程版本,考虑用户等待的时间， 除使用多条线程进行 GC外, 包括 Serial可用的所有控制参数、收集算法、STW、对象分配规则、回收策略等都与 Serial 完全一样(也是VM启用 CMS 收集器-XX: +UseConcMarkSweepGC 的默认新生代收集器)。</p>
<p>由于存在线程切换的开销, ParNew 在单 CPU 的环境中比不上 Serial, 且在通过超线程技术实现的两个 CPU 的环境中也不能 100%保证能超越 Serial. 但随着可用的 CPU 数量的增加,收集效率肯定也会大大增加(ParNew 收集线程数与 CPU 的数量相同, 因此在 CPU 数量过大的环境中, 可用-XX:ParallelGCThreads=<n>参数控制 GC 线程数，一般与CPU的线程数相同)。</n></p>
</li>
</ul>
<p><img src="\media\并行收集器.jpg" alt=""></p>
<ul>
<li><p>Parallel Scavenge 收集器：与 ParNew 类似, Parallel Scavenge 也是使用复制算法, 也是并行多线程收集器. 但与其他收集器关注尽可能缩短垃圾收集时间不同, Parallel Scavenge 更关注系统吞吐量:</p>
<ul>
<li><p>系统吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)</p>
</li>
<li><p>停顿时间越短就越适用于用户交互的程序-良好的响应速度能提升用户的体验;</p>
</li>
<li><p>而高吞吐量则适用于后台运算而不需要太多交互的任务-可以最高效率地利用CPU时间,尽快地完成程序的运算任务. </p>
</li>
<li><p>Parallel Scavenge 提供了如下参数设置系统吞吐量:</p>
<p><img src="\media\Parallel Scavenge 参数.jpg" alt=""></p>
</li>
</ul>
</li>
<li><p>Serial Old 收集器：Serial Old 是 Serial 收集器的老年代版本, 同样是单线程收集器,使用“标记-整理”算法</p>
</li>
</ul>
<p><img src="\media\Serial Old收集器.jpg" alt=""></p>
<ul>
<li>Parallel Old 收集器：Parallel Old 是 Parallel Scavenge 收集器的老年代版本, 使用多线程和“标记－整理”算<br>法, 吞吐量优先, 主要与 Parallel Scavenge 配合在注重吞吐量及 CPU 资源敏感系统内使用；</li>
</ul>
<p><img src="\media\Parallel Old 收集器.jpg" alt=""></p>
<ul>
<li><p>CMS 收集器 （Concurrent Mark Sweep ）：CMS(Concurrent Mark Sweep)收集器是一款具有划时代意义的收集器, 一款真正意义上的并发收集器, 虽然现在已经有了理论意义上表现更好的 G1 收集器, 但现在主流互联网企业线上选用的仍是 CMS(如 Taobao、微店)。</p>
<ul>
<li>并发（concurrent）包含用户线程，并行（Parallel）不包含。</li>
<li>CMS是一种以获取最短回收停顿时间为目标的收集器(CMS又称多并发低暂停的收集器)，基于”标记-清除”算法实现， 整个 GC 过程分为以下 4 个步骤:<ul>
<li>初始标记(CMS initial mark)</li>
<li>并发标记(CMS concurrent mark: GC Roots Tracing 过程)</li>
<li>重新标记(CMS remark)</li>
<li>并发清除(CMS concurrent sweep: 已死对象将会就地释放, 注意:此处没有压缩)</li>
</ul>
</li>
<li>其中 1，3 两个步骤(初始标记、重新标记)仍需 STW. 但初始标记仅只标记一下 GC Roots能直接关联到的对象, 速度很快; 而重新标记则是为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录, 虽然一般比初始标记阶段稍长, 但要远小于并发标记时间。CMS 特点：<ul>
<li>CMS 默认启动的回收线程数=(CPU 数目+3)4，当 CPU 数&gt;4 时, GC线程一般占用不超过 25%的 CPU 资源, 但是当 CPU 数&lt;=4 时, GC线程可能就会过多的占用用户 CPU 资源, 从而导致应用程序变慢, 总吞吐量降低。</li>
<li>无法处理浮动垃圾, 可能出现 Promotion Failure、Concurrent Mode Failure 而导致另一<br>次 Full GC 的产生: 浮动垃圾是指在 CMS 并发清理阶段用户线程运行而产生的新垃圾. 由于<br>在 GC 阶段用户线程还需运行, 因此还需要预留足够的内存空间给用户线程使用, 导致 CMS<br>不 能 像 其 他收 集 器那 样 等到 老 年 代几 乎 填满 了 再进 行 收 集. 因此 CMS 提 供 了<br>-XX:CMSInitiatingOccupancyFraction 参 数 来 设 置 GC 的 触 发 百 分 比 ( 以 及<br>-XX:+UseCMSInitiatingOccupancyOnly 来启用该触发百分比), 当老年代的使用空间超过该比例<br>后 CMS 就会被触发(JDK 1.6 之后默认 92%). 但当 CMS 运行期间预留的内存无法满足程序需<br>要, 就会出现上述 Promotion Failure 等失败, 这时 VM 将启动后备预案: 临时启用 Serial Old<br>收集器来重新执行Full GC(CMS通常配合大内存使用, 一旦大内存转入串行的Serial GC, 那停<br>顿的时间就是大家都不愿看到的了).</li>
<li>最后, 由于 CMS 采用”标记-清除”算法实现, 可能会产生大量内存碎片. 内存碎片过<br>多 可 能 会 导 致 无 法 分 配 大 对 象 而 提 前 触 发 Full GC. 因 此 CMS 提 供 了<br>-XX:+UseCMSCompactAtFullCollection 开关参数, 用于在 Full GC 后再执行一个碎片整理过程.<br>但内存整理是无法并发的, 内存碎片问题虽然没有了, 但停顿时间也因此变长了, 因此 CMS<br>还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction 用于设置在执行 N 次不进行内存整<br>理的 Full GC 后, 跟着来一次带整理的(默认为 0: 每次进入 Full GC 时都进行碎片整理).</li>
</ul>
</li>
</ul>
<p><img src="\media\CMS收集器.jpg" alt=""></p>
</li>
<li><p>分区收集- G1 收集器：G1(Garbage-First)是一款面向服务端应用的收集器, 主要目标用于配备多颗 CPU 的服务器治理大内存，-XX:+UseG1GC 启用 G1 收集器。</p>
<ul>
<li>与其他基于分代的收集器不同, G1 将整个 Java 堆划分为多个大小相等的独立区域(Region), 虽然还保留有新生代和老年代的概念, 但新生代和老年代不再是物理隔离的了,它们都是一部分 Region(不需要连续)的集合.如：</li>
</ul>
<p><img src="\media\G1.jpg" alt=""></p>
<ul>
<li><p>每块区域既有可能属于 O 区、也有可能是 Y 区，因此不需要一次就对整个老年代/新生代回收。而是当线程并发寻找可回收的对象时，有些区块包含可回收的对象要比其他区块多很多。 虽然在清理这些区块时 G1 仍然需要暂停应用线程,，但可以用相对较少的时间优先回收垃圾较多的 Region。这种方式保证了 G1 可以在有限的时间内获取尽可能高的收集效率。</p>
</li>
<li><p>G1的新生代收集跟ParNew类似: 存活的对象被转移到一个或多个Survivor Regions.，如果存活时间达到阀值, 这部分对象就会被提升到老年代.如图：</p>
<p><img src="\media\G11.jpg" alt=""></p>
</li>
<li><p>其特定是：</p>
<ul>
<li>一整块堆内存被分为多个 Regions.</li>
<li>存活对象被拷贝到新的 Survivor 区或老年代.</li>
<li>年轻代内存由一组不连续的 heap 区组成, 这种方法使得可以动态调整各代区域尺寸.</li>
<li>Young GC 会有 STW 事件, 进行时所有应用程序线程都会被暂停.</li>
<li>多线程并发 GC.</li>
</ul>
</li>
<li><p>G1 老年代 GC 特点如下 :</p>
<ul>
<li>并发标记阶段<ol>
<li>在与应用程序并发执行的过程中会计算活跃度信息 .</li>
<li>这些活跃度信息标识出那些 regions 最适合在 STW 期间回收 (which regions will be best<br>to reclaim during an evacuation pause).</li>
<li>不像 CMS 有清理阶段 .</li>
</ol>
</li>
<li>再次标记阶段<ol>
<li>使用 Snapshot-at-the-Beginning(SATB) 算法比 CMS 快得多 .</li>
<li>空 region 直接被回收 .</li>
</ol>
</li>
<li>拷贝 / 清理阶段 (Copying/Cleanup Phase)<ol>
<li>年轻代与老年代同时回收 .</li>
<li>老年代内存回收会基于他的活跃度信息</li>
</ol>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="化神圆满（JVM优化）"><a href="#化神圆满（JVM优化）" class="headerlink" title="化神圆满（JVM优化）"></a>化神圆满（JVM优化）</h3><p><strong>JDK 常用 JVM 优化相关命令</strong></p>
<p><img src="\media\JVM相关命令.jpg" alt=""></p>
<ul>
<li><p>jps</p>
<ul>
<li>jps - l：显示线程 id 和执行线程的主类名</li>
<li>jps -v：显示线程 id 和执行线程的主类名和 JVM 配置信息</li>
</ul>
</li>
<li><p>jstat</p>
<ul>
<li>jstat -参数 线程 id 执行时间（单位毫秒） 执行次数</li>
<li>如：jstat -gc 4488 30 10<ul>
<li>SXC - survivor 初始空间大小，单位字节。（X为survivor中X区域）</li>
<li>SXU - survivor 使用空间大小， 单位字节。</li>
<li>EC - eden 初始空间大小</li>
<li>EU - eden 使用空间大小</li>
<li>OC - old 初始空间大小</li>
<li>OU - old 使用空间大小</li>
<li>PC - permanent 初始空间大小</li>
<li>PU - permanent 使用空间大小</li>
<li>YGC - youngGC 收集次数</li>
<li>YGCT - youngGC 收集使用时长， 单位秒</li>
<li>FGC - fullGC 收集次数</li>
<li>FGCT - fullGC 收集使用时长</li>
<li>GCT - 总计收集使用总时长 YGCT+FGCT</li>
</ul>
</li>
</ul>
</li>
<li><p>jvisualvm：一个 JDK 内置的图形化 VM 监视管理工具。一般我们会在里面安装visualgc 插件。（工具、插件、可用插件），设置编辑url连接地址。</p>
<p><strong>JVM 常见参数</strong><br><em>配置方式：java [options] MainClass [arguments]<br>options - JVM 启动参数。 配置多个参数的时候，参数之间使用空格分隔。<br>参数命名： 常见为 -参数名<br>参数赋值： 常见为 -参数名=参数值 | -参数名:参数值</em></p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        List&lt;GarbageCollectorMXBean&gt; l = ManagementFactory.getGarbageCollectorMXBeans();  </span><br><span class="line">        <span class="keyword">for</span>(GarbageCollectorMXBean b : l) &#123;  </span><br><span class="line">            System.out.println(b.getName());  <span class="comment">// 收集器名称</span></span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.in.read();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><p>内存设置</p>
<ul>
<li>-Xms:初始堆大小，JVM 启动的时候，给定堆空间大小。</li>
<li>-Xmx:最大堆大小，JVM 运行过程中，如果初始堆空间不足的时候，最大可以扩展到多少。</li>
<li>-Xmn：设置年轻代大小。整个堆大小=年轻代大小+年老代大小+持久代大小。持久代一般固定大小为 64m，所以增大年轻代后，将会减小年老代大小。此值对系统性能影响较大，Sun 官方推荐配置为整个堆的 3/8。</li>
<li>-Xss： 设置每个线程的 Java 栈大小。JDK5.0 以后每个线程 Java 栈大小为 1M，以前每个线程堆栈大小为 256K。根据应用的线程所需内存大小进行调整。在相同物理内存下，减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的，不能无限生成，经验值在 3000~5000 左右。</li>
<li>-XX:NewSize=n:设置年轻代大小</li>
<li>-XX:NewRatio=n:设置年轻代和年老代的比值。如:为 3，表示年轻代与年老代比值为 1：3，年轻代占整个年轻代+年老代和的 1/4</li>
<li>-XX:SurvivorRatio=n:年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。如：3，表示 Eden：Survivor=3：2，一个 Survivor 区占整个年轻代的 1/5</li>
<li>-XX:MaxPermSize=n:设置持久代大小</li>
<li>-XX:MaxTenuringThreshold：设置垃圾最大年龄。如果设置为 0 的话，则年轻代对象不经过 Survivor区，直接进入年老代。对于年老代比较多的应用，可以提高效率。如果将此值设置为一个较大值，则年轻代对象会在 Survivor 区进行多次复制，这样可以增加对象再年轻代的存活时间，增加在年轻代即被回收的概率。</li>
</ul>
</li>
<li><p>收集器设置</p>
<ul>
<li>-XX:+UseSerialGC:设置串行收集器，年轻带收集器， 次收集器</li>
<li>-XX:+UseParallelGC:设置并行收集器</li>
<li>-XX:+UseParNewGC:设置年轻代为并行收集。可与 CMS 收集同时使用。JDK5.0 以上，JVM会根据系统配置自行设置，所以无需再设置此值。</li>
<li>-XX:+UseParallelOldGC:设置并行年老代收集器，JDK6.0 支持对年老代并行收集。</li>
<li>-XX:+UseConcMarkSweepGC:设置年老代并发收集器，测试中配置这个以后，-XX:NewRatio的配置失效，原因不明。所以，此时年轻代大小最好用-Xmn 设置。</li>
<li>-XX:+UseG1GC:设置 G1 收集器</li>
</ul>
</li>
<li><p>垃圾回收统计信息，类似日志的配置信息。会有控制台相关信息输出。 商业项目上线的时候，使用 loggc</p>
<ul>
<li>-XX:+PrintGC</li>
<li>-XX:+Printetails</li>
<li>-XX:+PrintGCTimeStamps</li>
<li>-Xloggc:filename</li>
</ul>
</li>
<li><p>并行收集器设置</p>
<ul>
<li>-XX:ParallelGCThreads=n:设置并行收集器收集时最大线程数使用的 CPU 数。并行收集线程数。</li>
<li>-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间，单位毫秒。可以减少 STW 时间。</li>
<li>-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为 1/(1+n)并发收集器设置</li>
<li>-XX:+CMSIncrementalMode:设置为增量模式。适用于单 CPU 情况。</li>
<li>-XX:+UseAdaptiveSizePolicy：设置此选项后，并行收集器会自动选择年轻代区大小和相应的 Survivor 区比例，以达到目标系统规定的最低相应时间或者收集频率等，此值建议使用并行收集器时，一直打开。</li>
<li>-XX:CMSFullGCsBeforeCompaction=n：由于并发收集器不对内存空间进行压缩、整理，所以运行一段时间以后会产生“碎片”，使得运行效率降低。此值设置运行多少次 GC 以后对内存空间进行压缩、整理。</li>
<li>-XX:+UseCMSCompactAtFullCollection：打开对年老代的压缩。可能会影响性能，但是可<br>以消除碎片</li>
</ul>
</li>
<li><p>内存设置经验分享</p>
<ul>
<li>JVM 中最大堆大小有三方面限制：<ul>
<li>相关操作系统的数据模型（32-bt 还是 64-bit）限制；</li>
<li>系统的可用虚拟内存限制；</li>
<li>系统的可用物理内存限制。</li>
<li>32 位系统 下，一般限制在 1.5G~2G；64 为操作系统对内存无限制。</li>
</ul>
</li>
<li>Tomcat 配置方式： 编写 catalina.bat|catalina.sh ，增加 JAVA_OPTS 参数设置。 windows和 linux 配置方式不同。 windows - set “JAVA_OPTS=%JAVA_OPTS% 自定义参数 “ ； linux -JAVA_OPTS=”$JAVA_OPTS 自定义参数 “常见设置：<ul>
<li>-Xmx3550m -Xms3550m -Xmn2g -Xss128k 适合开发过程的测试应用。要求物理内存大于4G。<ul>
<li>设置JVM最大可用内存与初始内存相同，可以避免每次垃圾完成后JVM重新分配内存。</li>
<li>-Xmn2g，设置年轻代为2个g，持久代一般固定大小为64m，所以增大年轻代后，将会减小老年代大小。官方推荐设置成整个堆的3/8。</li>
<li>-Xss128k ，设置每个线程的堆栈大小，JDK1.5后每个线程栈大小为1M，以前每个线程栈大小为256k。在相同物理内存下，减少这个值能生成更多的线程，但是操作系统对进程内的线程数量是有限的，不能无线生成，经验值在3000~5000左右。</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>收集器设置经验分享</p>
<ul>
<li>关于收集器的选择 JVM 给了三种选择：串行收集器、并行收集器、并发收集器，但是串行收集器只适用于小数据量的情况，所以这里的选择主要针对并行收集器和并发收集器。默认情况下，JDK5.0 以前都是使用串行收集器，如果想使用其他收集器需要在启动时加入相应参数。JDK5.0 以后，JVM 会根据当前系统配置进行判断。</li>
<li>常见配置：<ul>
<li>并行收集器主要以到达一定的吞吐量为目标，适用于科学计算和后台处理等。</li>
<li>-Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20</li>
<li>使用 ParallelGC 作为并行收集器， GC 线程为 20（CPU 核心数&gt;=20 时），内存问题根据硬件配置具体提供。建议使用物理内存的 80%左右作为 JVM 内存容量。</li>
<li>-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20<br>-XX:+UseParallelOldGC</li>
<li>指定老年代收集器，在JDK5.0之后的版本，ParallelGC对应的全收集器就是ParallelOldGC。可以忽略</li>
<li>-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100</li>
<li>指定 GC 时最大暂停时间。单位是毫秒。每次 GC 最长使用 100 毫秒。可以尽可能提高工作线程的执行资源。</li>
<li>-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100<br>-XX:+UseAdaptiveSizePolicy</li>
<li>UseAdaptiveSizePolicy 是提高年轻代 GC 效率的配置。次收集器执行效率。</li>
<li>并发收集器主要是保证系统的响应时间，减少垃圾收集时的停顿时间。适用于应用服务<br>器、电信领域、互联网领域等。</li>
<li>-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20<br>-XX:+UseConcMarkSweepGC -XX:+UseParNewGC</li>
<li>指定年轻代收集器为 ParNew，年老代收集器 ConcurrentMarkSweep，并发 GC 线程数为20（CPU 核心&gt;=20），并发 GC 的线程数建议使用（CPU 核心数+3）/4 或 CPU 核心数【不推荐使用】。</li>
<li>-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC<br>-XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection</li>
<li>CMSFullGCsBeforeCompaction=5 执行 5 次 GC 后，运行一次内存的整理。</li>
<li>UseCMSCompactAtFullCollection 执行老年代内存整理。可以避免内存碎片，提高 GC 过程中的效率，减少停顿时间。</li>
</ul>
</li>
</ul>
</li>
<li><p>简单总结</p>
<ul>
<li>年轻代大小选择<ul>
<li>响应时间优先的应用：尽可能设大，直到接近系统的最低响应时间限制（根据实际情况选择）。在此种情况下，年轻代收集发生的频率也是最小的。同时，减少到达年老代的对象。</li>
<li>吞吐量优先的应用：尽可能的设置大，可能到达 Gbit 的程度。因为对响应时间没有要求，垃圾收集可以并行进行，一般适合 8CPU 以上的应用。</li>
</ul>
</li>
<li>年老代大小选择<ul>
<li>响应时间优先的应用： 年老代使用并发收集器，所以其大小需要小心设置，一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了，可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式；如果堆大了，则需要较 长的收集时间。最优化的方案，一般需要参考以下数据获得：<ul>
<li>并发垃圾收集信息</li>
<li>持久代并发收集次数</li>
<li>传统 GC 信息</li>
<li>花在年轻代和年老代回收上的时间比例</li>
<li>减少年轻代和年老代花费的时间，一般会提高应用的效率</li>
</ul>
</li>
<li>吞吐量优先的应用：一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是，这样可以尽可能回收掉大部分短期对象，减少中期的对象，而年老代存放长期存活对象。</li>
<li>较小堆引起的碎片问题，因为年老代的并发收集器使用标记、清除算法，所以不会对堆进行压缩。当收集器回收时，他会把相邻的空间进行合并，这样可以分配给较大的对象。但是，当堆空间较小时，运行一段时间以后，就会出现“碎片”，如果并发收集器找不到足够的空间，那么并发收集器将会停止，然后使用传统的标记、整理方式进行回收。如果出现“碎片”，可能需要进行如下配置：<ul>
<li>-XX:+UseCMSCompactAtFullCollection：使用并发收集器时，开启对年老代的压缩。</li>
<li>-XX:CMSFullGCsBeforeCompaction=0：上面配置开启的情况下，这里设置多少次 Full GC后，对年老代进行压缩</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><em>小编是一枚Java Coder，业余写文章，现主营微信公众号《Java患者》，喜欢的话关注我的公众号或者加我微信我们一起学习Java</em></p>
<p><img src="\111公众号.jpg" alt=""></p>
<h2 id="合体期（网络编程）"><a href="#合体期（网络编程）" class="headerlink" title="合体期（网络编程）"></a>合体期（网络编程）</h2><h3 id="合体前期（Socket）"><a href="#合体前期（Socket）" class="headerlink" title="合体前期（Socket）"></a>合体前期（Socket）</h3><p>​            <em>首先注意，Socket不是Java中独有的概念，而是一个语言无关标准。任何可以实现网络编程的编程语言都有Socket。</em> </p>
<ul>
<li><p><strong>什么是</strong> <strong>Socket?</strong> </p>
<blockquote>
<p>​        网络上的两个程序通过一个双向的通信连接实现数据的交换，这个连接的一端称为一个socket。 </p>
<p>​        建立网络通信连接至少要一个端口号。<em>socket</em> 本质是编程接口<em>(API)</em>，对 <em>TCP/IP</em> 的封装，<em>TCP/IP</em> 也要提供可供程序员做网络开发所用的接口，这就是 <em>Socket</em> 编程接口；<em>HTTP</em> 是轿车， 提供了封装或者显示数据的具体形式；<em>Socket</em> 是发动机，提供了网络通信的能力。 </p>
<p>​        <em>Socket</em> 的英文原义是<em>“</em>孔<em>”</em>或<em>“</em>插座<em>”</em>。作为 <em>BSD UNIX</em> 的进程通信机制，取后一种意思。通 常也称作<em>“</em>套接字<em>“</em>，用于描述 <em>IP</em> 地址和端口，是一个通信链的句柄，可以用来实现不同虚 拟机或不同计算机之间的通信。在 <em>Internet</em> 上的主机一般运行了多个服务软件，同时提供几 种服务。每种服务都打开一个 <em>Socket</em>，并绑定到一个端口上，不同的端口对应于不同的服务。<em>Socket</em> 正如其英文原义那样，像一个多孔插座。一台主机犹如布满各种插座的房间，每个插 座有一个编号，有的插座提供 <em>220</em> 伏交流电， 有的提供 <em>110</em> 伏交流电，有的则提供有线电 视节目。 客户软件将插头插到不同编号的插座，就可以得到不同的服务。</p>
</blockquote>
</li>
<li><p><strong>Socket</strong> <strong>连接步骤</strong> </p>
<p>​        <em>根据连接启动的方式以及本地套接字要连接的目标，套接字之间的连接过程可以分为三个步骤：服务器监听，客户端请求，连接确认。【如果包含数据交互+断开连接，那么一共是 五个步骤】</em></p>
<ol>
<li>服务器监听：是服务器端套接字并不定位具体的客户端套接字，而是处于等待连接的状态，实时监控网络状态。 </li>
<li>客户端请求：是指由客户端的套接字提出连接请求，要连接的目标是服务器端的套接字。为此，客户端的套接字必须首先描述它要连接的服务器的套接字，指出服务器端套接字的地址和端口号，然后就向服务器端套接字提出连接请求。 </li>
<li>连接确认(三层握手)：是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求【1】，它就响应客户端套接字的请求，建立一个新的线程，把服务器端套接字的描述发给客户端【2】，一旦客户端确认了此描述，连接就建立好了【3】。而服务器端套接字继续处于监听状态，继续接收其他客户端套接字的连接请求。</li>
<li>断开连接：客户端向服务发起一个请求关闭消息【1】，服务器根据自己状态，等到可以关闭时候，发一个可以关闭的消息给客户端【2】，并且服务器再向浏览器发一个关闭成功的消息【3】，客户端发一个光笔成功的消息，至于服务器可以收到不管【4】。</li>
</ol>
<p><img src="\media\握手和挥手.jpg" alt=""></p>
</li>
<li><p><strong>Java</strong> <strong>中的</strong> <strong>Socket</strong> </p>
<p>​        <em>在java.net包是网络编程的基础类库。其中ServerSocket和Socket是网络编程的基础类型ServerSocket是服务端应用类型。Socket是建立连接的类型。当连接建立成功后，服务器和客户端都会有一个 Socket对象示例，可以通过这个Socket 对象示例，完成会话的所有操作。</em></p>
<p>​        <em>对于一个完整的网络连接来说，Socket是平等的，没有服务器客户端分级情况</em></p>
</li>
<li><p><strong>什么是同步和异步</strong> </p>
<p>​        同步和异步是针对应用程序和内核OS的交互而言的，同步指的是用户进程触发 <em>IO</em> 操作并 等待或者轮询的去查看 <em>IO</em> 操作是否就绪，而异步是指用户进程触发 <em>IO</em> 操作以后便开始做自 己的事情，而当 <em>IO</em> 操作已经完成的时候会得到 <em>IO</em> 完成的通知，异步是OS底层支持的一种操作。以银行取款为例： </p>
<ul>
<li>同步 ： 自己亲自出马持银行卡到银行取钱（使用同步 <em>IO</em> 时，<em>Java</em> 自己处理 <em>IO</em> 读写）； </li>
<li>异步 ： 委托一小弟拿银行卡到银行取钱，然后给你（使用异步 <em>IO</em> 时，<em>Java</em> 将 <em>IO</em> 读写 委托给 <em>OS</em> 处理，需要将数据缓冲区地址和大小传给 <em>OS(</em>银行卡和密码<em>)</em>，<em>OS</em> 需要支持异步 <em>IO</em> 操作 <em>API</em>）</li>
</ul>
</li>
<li><p><strong>什么是阻塞和非阻塞</strong> </p>
<p>​        阻塞和非阻塞是针对于进程在访问数据的时候，根据 <em>IO</em> 操作的就绪状态来采取的不同 方式，说白了是一种读取或者写入操作方法的实现方式，阻塞方式下读取或者写入函数将一直等待，而非阻塞方式下，读取或者写入方法会立即返回一个状态值。 以银行取款为例： </p>
<ul>
<li>阻塞 ： <em>ATM</em> 排队取款，你只能等待（使用阻塞 <em>IO</em> 时，<em>Java</em> 调用会一直阻塞到读写完 成才返回）； </li>
<li>非阻塞 ： 柜台取款，取个号，然后坐在椅子上做其它事，等号广播会通知你办理，没到号你就不能去，你可以不断问大堂经理排到了没有，大堂经理如果说还没到你就不能去（使用非阻塞 <em>IO</em> 时，如果不能读写 <em>Java</em> 调用会马上返回，当 <em>IO</em> 事件分发器通知可读写时再继 续进行读写，不断循环直到读写完成）</li>
<li>ajax是异步阻塞的。</li>
</ul>
</li>
</ul>
<h3 id="合体中期（BIO、NIO-、AIO）"><a href="#合体中期（BIO、NIO-、AIO）" class="headerlink" title="合体中期（BIO、NIO 、AIO）"></a>合体中期（BIO、NIO 、AIO）</h3><ul>
<li><p><strong>BIO</strong> <strong>编程</strong> ：<em>Blocking IO</em>同步阻塞的编程方式。 </p>
<ul>
<li><em>BIO</em> 编程方式通常是在 <em>JDK1.4</em> 版本之前常用的编程方式。编程实现过程为：首先在服务端启动一个 <em>ServerSocket</em> 来监听网络请求，客户端启动 <em>Socket</em> 发起网络请求，默认情况下 <em>ServerSocket</em> 回建立一个线程来处理此请求，如果服务端没有线程可用，客户端则会阻塞等待或遭到拒绝。 且建立好的连接，在通讯过程中，是同步的。在并发处理效率上比较低。大致结构如下：</li>
</ul>
<p><img src="\media\BIO结构.jpg" alt=""></p>
<ul>
<li><p>每次请求都要创建一个server socket和一个thread</p>
</li>
<li><p>同步并阻塞，服务器实现模式为一个连接一个线程，即客户端有连接请求时服务器端就 需要启动一个线程进行处理，如果这个连接不做任何事情会造成不必要的线程开销，当然可 以通过线程池机制改善（有人把这种叫做伪异步，实际上不能实现任何的异步的操作，归根还是同步）。</p>
</li>
<li><p><em>BIO</em> 方式适用于连接数目比较小且固定的架构，这种方式对服务器资源要求比较高，并发局限于应用中，<em>JDK1.4</em> 以前的唯一选择，但程序直观简单易理解。</p>
</li>
<li><p>使用线程池机制改善后的 <em>BIO</em> 模型图如下<em>:</em> </p>
<p> <img src="\media\BIO线程池结果图.jpg" alt=""></p>
</li>
</ul>
</li>
</ul>
<p>Client：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        String host = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">int</span> port = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">if</span>(args.length &gt; <span class="number">2</span>)&#123;</span><br><span class="line">            host = args[<span class="number">0</span>];</span><br><span class="line">            port = Integer.parseInt(args[<span class="number">1</span>]);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            host = <span class="string">"127.0.0.1"</span>;</span><br><span class="line">            port = <span class="number">9999</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Socket socket = <span class="keyword">null</span>;</span><br><span class="line">        BufferedReader reader = <span class="keyword">null</span>;</span><br><span class="line">        PrintWriter writer = <span class="keyword">null</span>;</span><br><span class="line">        Scanner s = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            socket = <span class="keyword">new</span> Socket(host, port);</span><br><span class="line">            String message = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">            reader = <span class="keyword">new</span> BufferedReader(</span><br><span class="line">                    <span class="keyword">new</span> InputStreamReader(socket.getInputStream(), <span class="string">"UTF-8"</span>));</span><br><span class="line">            writer = <span class="keyword">new</span> PrintWriter(</span><br><span class="line">                    socket.getOutputStream(), <span class="keyword">true</span>);</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                message = s.nextLine();</span><br><span class="line">                <span class="keyword">if</span>(message.equals(<span class="string">"exit"</span>))&#123;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                writer.println(message);</span><br><span class="line">                writer.flush();</span><br><span class="line">                System.out.println(reader.readLine());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(socket != <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    socket.close();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            socket = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">if</span>(reader != <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    reader.close();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            reader = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">if</span>(writer != <span class="keyword">null</span>)&#123;</span><br><span class="line">                writer.close();</span><br><span class="line">            &#125;</span><br><span class="line">            writer = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> port = genPort(args);</span><br><span class="line"></span><br><span class="line">        ServerSocket server = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            server = <span class="keyword">new</span> ServerSocket(port);</span><br><span class="line">            System.out.println(<span class="string">"server started!"</span>);</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                Socket socket = server.accept();</span><br><span class="line"></span><br><span class="line">                <span class="keyword">new</span> Thread(<span class="keyword">new</span> Handler(socket)).start();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(server != <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    server.close();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            server = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Handler</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">        Socket socket = <span class="keyword">null</span>;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Handler</span><span class="params">(Socket socket)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.socket = socket;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            BufferedReader reader = <span class="keyword">null</span>;</span><br><span class="line">            PrintWriter writer = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line"></span><br><span class="line">                reader = <span class="keyword">new</span> BufferedReader(</span><br><span class="line">                        <span class="keyword">new</span> InputStreamReader(socket.getInputStream(), <span class="string">"UTF-8"</span>));</span><br><span class="line">                writer = <span class="keyword">new</span> PrintWriter(</span><br><span class="line">                        <span class="keyword">new</span> OutputStreamWriter(socket.getOutputStream(), <span class="string">"UTF-8"</span>));</span><br><span class="line">                String readMessage = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                    System.out.println(<span class="string">"server reading... "</span>);</span><br><span class="line">                    <span class="keyword">if</span>((readMessage = reader.readLine()) == <span class="keyword">null</span>)&#123;</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(readMessage);</span><br><span class="line">                    writer.println(<span class="string">"server recive : "</span> + readMessage);</span><br><span class="line">                    writer.flush();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">                <span class="keyword">if</span>(socket != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        socket.close();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                socket = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">if</span>(reader != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        reader.close();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                reader = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">if</span>(writer != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    writer.close();</span><br><span class="line">                &#125;</span><br><span class="line">                writer = <span class="keyword">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">genPort</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(args.length &gt; <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                <span class="keyword">return</span> Integer.parseInt(args[<span class="number">0</span>]);</span><br><span class="line">            &#125;<span class="keyword">catch</span>(NumberFormatException e)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="number">9999</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">9999</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>ThreadPool版的Server</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> port = genPort(args);</span><br><span class="line"></span><br><span class="line">        ServerSocket server = <span class="keyword">null</span>;</span><br><span class="line">        ExecutorService service = Executors.newFixedThreadPool(<span class="number">50</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            server = <span class="keyword">new</span> ServerSocket(port);</span><br><span class="line">            System.out.println(<span class="string">"server started!"</span>);</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                Socket socket = server.accept();</span><br><span class="line"></span><br><span class="line">                service.execute(<span class="keyword">new</span> Handler(socket));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(server != <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    server.close();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            server = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Handler</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">        Socket socket = <span class="keyword">null</span>;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Handler</span><span class="params">(Socket socket)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.socket = socket;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            BufferedReader reader = <span class="keyword">null</span>;</span><br><span class="line">            PrintWriter writer = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line"></span><br><span class="line">                reader = <span class="keyword">new</span> BufferedReader(</span><br><span class="line">                        <span class="keyword">new</span> InputStreamReader(socket.getInputStream(), <span class="string">"UTF-8"</span>));</span><br><span class="line">                writer = <span class="keyword">new</span> PrintWriter(</span><br><span class="line">                        <span class="keyword">new</span> OutputStreamWriter(socket.getOutputStream(), <span class="string">"UTF-8"</span>));</span><br><span class="line">                String readMessage = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                    System.out.println(<span class="string">"server reading... "</span>);</span><br><span class="line">                    <span class="keyword">if</span>((readMessage = reader.readLine()) == <span class="keyword">null</span>)&#123;</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(readMessage);</span><br><span class="line">                    writer.println(<span class="string">"server recive : "</span> + readMessage);</span><br><span class="line">                    writer.flush();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">                <span class="keyword">if</span>(socket != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        socket.close();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                socket = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">if</span>(reader != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        reader.close();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                reader = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">if</span>(writer != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    writer.close();</span><br><span class="line">                &#125;</span><br><span class="line">                writer = <span class="keyword">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">genPort</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(args.length &gt; <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                <span class="keyword">return</span> Integer.parseInt(args[<span class="number">0</span>]);</span><br><span class="line">            &#125;<span class="keyword">catch</span>(NumberFormatException e)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="number">9999</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">9999</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><p><strong>NIO</strong> <strong>编程</strong> <em>Unblocking IO</em>（<em>New IO</em>）： 同步非阻塞的编程方式。 </p>
<ul>
<li><p><em>NIO</em> 本身是基于事件驱动思想来完成的，其主要想解决的是 <em>BIO</em> 的大并发问题，<em>NIO</em> 基于<em>Reactor</em>，当 <em>socket</em> 有流可读或可写入 <em>socket</em> 时，操作系统会相应的通知应用程序进行处理，应用再将流读取到缓冲区或写入操作系统。也就是说，这个时候，已经不是一个连接就要对应一个处理线程了，而是有效的请求，对应一个线程，当连接没有数据时，是没有工作线程来处理的（即一个线程对应多个有效请求）。</p>
</li>
<li><p><em>NIO</em> 的最重要的地方是当一个连接创建后，不需要对应一个线程，这个连接会被注册到多路复用器上面，所以所有的连接只需要一个线程就可以搞定，当这个线程中的多路复用器进行轮询的时候，发现连接上有请求的话，才开启一个线程进行处理，也就是一个请求一个线程模式，并且面向缓存。 </p>
</li>
<li><p>在 <em>NIO</em> 的处理方式中，当一个请求来的话，开启线程进行处理，可能会等待后端应用的资源<em>(JDBC</em> 连接等待<em>)</em>，其实这个线程就被阻塞了，当并发上来的话，还是会有 <em>BIO</em> 一样的问题。 </p>
<p><img src="\media\NIO.jpg" alt=""></p>
</li>
<li><p>同步非阻塞，服务器实现模式为一个请求一个通道，即客户端发送的连接请求都会注册 到多路复用器上，多路复用器轮询到连接有 <em>I/O</em> 请求时才启动一个线程进行处理。 </p>
</li>
<li><p><em>NIO</em> 方式适用于连接数目多且连接比较短（轻操作）的架构，比如聊天服务器，并发局 限于应用中，编程复杂，<em>JDK1.4</em> 开始支持。 </p>
</li>
<li><p><strong><em>Buffer:ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer<em>*</em></em></strong>。<em>*</em></p>
</li>
<li><p><strong><em>Channel:SocketChannel,ServerSocketChannel<em>*</em></em></strong>。<em>*</em> </p>
</li>
<li><p><strong><em>Selector:Selector,AbstractSelector</em></strong> </p>
</li>
<li><p><strong><em>SelectionKey:OP_READ,OP_WRITE,OP_CONNECT,OP_ACCEPT</em></strong></p>
</li>
</ul>
</li>
</ul>
<p>client</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NIOClient</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 远程地址创建</span></span><br><span class="line">        InetSocketAddress remote = <span class="keyword">new</span> InetSocketAddress(<span class="string">"localhost"</span>, <span class="number">9999</span>);</span><br><span class="line">        SocketChannel channel = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 定义缓存。</span></span><br><span class="line">        ByteBuffer buffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 开启通道</span></span><br><span class="line">            channel = SocketChannel.open();</span><br><span class="line">            <span class="comment">// 连接远程服务器。</span></span><br><span class="line">            channel.connect(remote);</span><br><span class="line">            Scanner reader = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                System.out.print(<span class="string">"put message for send to server &gt; "</span>);</span><br><span class="line">                String line = reader.nextLine();</span><br><span class="line">                <span class="keyword">if</span>(line.equals(<span class="string">"exit"</span>))&#123;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 将控制台输入的数据写入到缓存。</span></span><br><span class="line">                buffer.put(line.getBytes(<span class="string">"UTF-8"</span>));</span><br><span class="line">                <span class="comment">// 重置缓存游标</span></span><br><span class="line">                buffer.flip();</span><br><span class="line">                <span class="comment">// 将数据发送给服务器</span></span><br><span class="line">                channel.write(buffer);</span><br><span class="line">                <span class="comment">// 清空缓存数据。</span></span><br><span class="line">                buffer.clear();</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 读取服务器返回的数据</span></span><br><span class="line">                <span class="keyword">int</span> readLength = channel.read(buffer);</span><br><span class="line">                <span class="keyword">if</span>(readLength == -<span class="number">1</span>)&#123;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 重置缓存游标</span></span><br><span class="line">                buffer.flip();</span><br><span class="line">                <span class="keyword">byte</span>[] datas = <span class="keyword">new</span> <span class="keyword">byte</span>[buffer.remaining()];</span><br><span class="line">                <span class="comment">// 读取数据到字节数组。</span></span><br><span class="line">                buffer.get(datas);</span><br><span class="line">                System.out.println(<span class="string">"from server : "</span> + <span class="keyword">new</span> String(datas, <span class="string">"UTF-8"</span>));</span><br><span class="line">                <span class="comment">// 清空缓存。</span></span><br><span class="line">                buffer.clear();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != channel)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    channel.close();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NIOServer</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 多路复用器， 选择器。 用于注册通道的。</span></span><br><span class="line">    <span class="keyword">private</span> Selector selector;</span><br><span class="line">    <span class="comment">// 定义了两个缓存。分别用于读和写。 初始化空间大小单位为字节。</span></span><br><span class="line">    <span class="comment">// Buffer1是不安全的，要想安全模仿BIO，独立定义为Handler对象</span></span><br><span class="line">    <span class="keyword">private</span> ByteBuffer readBuffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line">    <span class="keyword">private</span> ByteBuffer writeBuffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> NIOServer(<span class="number">9999</span>)).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">NIOServer</span><span class="params">(<span class="keyword">int</span> port)</span> </span>&#123;</span><br><span class="line">        init(port);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(<span class="keyword">int</span> port)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">"server starting at port "</span> + port + <span class="string">" ..."</span>);</span><br><span class="line">            <span class="comment">// 开启多路复用器</span></span><br><span class="line">            <span class="keyword">this</span>.selector = Selector.open();</span><br><span class="line">            <span class="comment">// 开启服务通道</span></span><br><span class="line">            ServerSocketChannel serverChannel = ServerSocketChannel.open();</span><br><span class="line">            <span class="comment">// 非阻塞， 如果传递参数true，为阻塞模式。</span></span><br><span class="line">            serverChannel.configureBlocking(<span class="keyword">false</span>);</span><br><span class="line">            <span class="comment">// 绑定端口</span></span><br><span class="line">            serverChannel.bind(<span class="keyword">new</span> InetSocketAddress(port));</span><br><span class="line">            <span class="comment">// 注册，并标记当前服务通道状态</span></span><br><span class="line">            <span class="comment">/*</span></span><br><span class="line"><span class="comment">             * register(Selector, int)</span></span><br><span class="line"><span class="comment">             * int - 状态编码</span></span><br><span class="line"><span class="comment">             *  OP_ACCEPT ： 连接成功的标记位。</span></span><br><span class="line"><span class="comment">             *  OP_READ ： 可以读取数据的标记</span></span><br><span class="line"><span class="comment">             *  OP_WRITE ： 可以写入数据的标记</span></span><br><span class="line"><span class="comment">             *  OP_CONNECT ： 连接建立后的标记</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line">            serverChannel.register(<span class="keyword">this</span>.selector, SelectionKey.OP_ACCEPT);</span><br><span class="line">            System.out.println(<span class="string">"server started."</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 阻塞方法，当至少一个通道被选中，此方法返回。</span></span><br><span class="line">                <span class="comment">// 通道是否选择，由注册到多路复用器中的通道标记决定。</span></span><br><span class="line">                <span class="keyword">this</span>.selector.select();</span><br><span class="line">                <span class="comment">// 返回以选中的通道标记集合， 集合中保存的是通道的标记。相当于是通道的ID。</span></span><br><span class="line">                Iterator&lt;SelectionKey&gt; keys = <span class="keyword">this</span>.selector.selectedKeys().iterator();</span><br><span class="line">                <span class="keyword">while</span>(keys.hasNext())&#123;</span><br><span class="line">                    SelectionKey key = keys.next();</span><br><span class="line">                    <span class="comment">// 将本次要处理的通道从集合中删除，下次循环根据新的通道列表再次执行必要的业务逻辑</span></span><br><span class="line">                    keys.remove();</span><br><span class="line">                    <span class="comment">// 通道是否有效</span></span><br><span class="line">                    <span class="keyword">if</span>(key.isValid())&#123;</span><br><span class="line">                        <span class="comment">// 阻塞状态</span></span><br><span class="line">                        <span class="keyword">try</span>&#123;</span><br><span class="line">                            <span class="keyword">if</span>(key.isAcceptable())&#123;</span><br><span class="line">                                accept(key);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;<span class="keyword">catch</span>(CancelledKeyException cke)&#123;</span><br><span class="line">                            <span class="comment">// 断开连接。 出现异常。</span></span><br><span class="line">                            key.cancel();</span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="comment">// 可读状态</span></span><br><span class="line">                        <span class="keyword">try</span>&#123;</span><br><span class="line">                            <span class="keyword">if</span>(key.isReadable())&#123;</span><br><span class="line">                                read(key);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;<span class="keyword">catch</span>(CancelledKeyException cke)&#123;</span><br><span class="line">                            key.cancel();</span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="comment">// 可写状态</span></span><br><span class="line">                        <span class="keyword">try</span>&#123;</span><br><span class="line">                            <span class="keyword">if</span>(key.isWritable())&#123;</span><br><span class="line">                                write(key);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;<span class="keyword">catch</span>(CancelledKeyException cke)&#123;</span><br><span class="line">                            key.cancel();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(SelectionKey key)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.writeBuffer.clear();</span><br><span class="line">        SocketChannel channel = (SocketChannel)key.channel();</span><br><span class="line">        Scanner reader = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.print(<span class="string">"put message for send to client &gt; "</span>);</span><br><span class="line">            String line = reader.nextLine();</span><br><span class="line">            <span class="comment">// 将控制台输入的字符串写入Buffer中。 写入的数据是一个字节数组。</span></span><br><span class="line">            writeBuffer.put(line.getBytes(<span class="string">"UTF-8"</span>));</span><br><span class="line">            writeBuffer.flip();</span><br><span class="line">            channel.write(writeBuffer);</span><br><span class="line"></span><br><span class="line">            channel.register(<span class="keyword">this</span>.selector, SelectionKey.OP_READ);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(SelectionKey key)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 清空读缓存。</span></span><br><span class="line">            <span class="keyword">this</span>.readBuffer.clear();</span><br><span class="line">            <span class="comment">// 获取通道</span></span><br><span class="line">            SocketChannel channel = (SocketChannel)key.channel();</span><br><span class="line">            <span class="comment">// 将通道中的数据读取到缓存中。通道中的数据，就是客户端发送给服务器的数据。</span></span><br><span class="line">            <span class="keyword">int</span> readLength = channel.read(readBuffer);</span><br><span class="line">            <span class="comment">// 检查客户端是否写入数据。</span></span><br><span class="line">            <span class="keyword">if</span>(readLength == -<span class="number">1</span>)&#123;</span><br><span class="line">                <span class="comment">// 关闭通道</span></span><br><span class="line">                key.channel().close();</span><br><span class="line">                <span class="comment">// 关闭连接</span></span><br><span class="line">                key.cancel();</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">/*</span></span><br><span class="line"><span class="comment">             * flip， NIO中最复杂的操作就是Buffer的控制。</span></span><br><span class="line"><span class="comment">             * Buffer中有一个游标。游标信息在操作后不会归零，如果直接访问Buffer的话，数据有不一致的可能。</span></span><br><span class="line"><span class="comment">             * flip是重置游标的方法。NIO编程中，flip方法是常用方法。</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line">            <span class="keyword">this</span>.readBuffer.flip();</span><br><span class="line">            <span class="comment">// 字节数组，保存具体数据的。 Buffer.remaining() -&gt; 是获取Buffer中有效数据长度的方法。</span></span><br><span class="line">            <span class="keyword">byte</span>[] datas = <span class="keyword">new</span> <span class="keyword">byte</span>[readBuffer.remaining()];</span><br><span class="line">            <span class="comment">// 是将Buffer中的有效数据保存到字节数组中。</span></span><br><span class="line">            readBuffer.get(datas);</span><br><span class="line">            System.out.println(<span class="string">"from "</span> + channel.getRemoteAddress() + <span class="string">" client : "</span> + <span class="keyword">new</span> String(datas, <span class="string">"UTF-8"</span>));</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 注册通道， 标记为写操作。</span></span><br><span class="line">            channel.register(<span class="keyword">this</span>.selector, SelectionKey.OP_WRITE);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                key.channel().close();</span><br><span class="line">                key.cancel();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e1) &#123;</span><br><span class="line">                e1.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">accept</span><span class="params">(SelectionKey key)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 此通道为init方法中注册到Selector上的ServerSocketChannel</span></span><br><span class="line">            ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel();</span><br><span class="line">            <span class="comment">// 阻塞方法，当客户端发起请求后返回。 此通道和客户端一一对应。</span></span><br><span class="line">            SocketChannel channel = serverChannel.accept();</span><br><span class="line">            channel.configureBlocking(<span class="keyword">false</span>);</span><br><span class="line">            <span class="comment">// 设置对应客户端的通道标记状态，此通道为读取数据使用的。</span></span><br><span class="line">            channel.register(<span class="keyword">this</span>.selector, SelectionKey.OP_READ);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>TestBuffer</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * Buffer的应用固定逻辑</span></span><br><span class="line"><span class="comment"> * 写操作顺序</span></span><br><span class="line"><span class="comment"> * 1. clear()</span></span><br><span class="line"><span class="comment"> * 2. put() -&gt; 写操作</span></span><br><span class="line"><span class="comment"> * 3. flip() -&gt; 重置游标</span></span><br><span class="line"><span class="comment"> * 4. SocketChannel.write(buffer); -&gt; 将缓存数据发送到网络的另一端</span></span><br><span class="line"><span class="comment"> * 5. clear()</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * 读操作顺序</span></span><br><span class="line"><span class="comment"> * 1. clear()</span></span><br><span class="line"><span class="comment"> * 2. SocketChannel.read(buffer); -&gt; 从网络中读取数据</span></span><br><span class="line"><span class="comment"> * 3. buffer.flip() -&gt; 重置游标</span></span><br><span class="line"><span class="comment"> * 4. buffer.get() -&gt; 读取数据</span></span><br><span class="line"><span class="comment"> * 5. buffer.clear()</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestBuffer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line"></span><br><span class="line">        ByteBuffer buffer = ByteBuffer.allocate(<span class="number">8</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">byte</span>[] temp = <span class="keyword">new</span> <span class="keyword">byte</span>[]&#123;<span class="number">3</span>,<span class="number">2</span>,<span class="number">1</span>&#125;;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 写入数据之前 ： java.nio.HeapByteBuffer[pos=0 lim=8 cap=8]</span></span><br><span class="line">        <span class="comment">// pos - 游标位置， lim - 限制数量， cap - 最大容量</span></span><br><span class="line">        System.out.println(<span class="string">"写入数据之前 ： "</span> + buffer);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 写入字节数组到缓存</span></span><br><span class="line">        buffer.put(temp);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 写入数据之后 ： java.nio.HeapByteBuffer[pos=3 lim=8 cap=8]</span></span><br><span class="line">        <span class="comment">// 游标为3， 限制为8， 容量为8，默认限制与容量一样大小</span></span><br><span class="line">        System.out.println(<span class="string">"写入数据之后 ： "</span> + buffer);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 重置游标 ， lim = pos ;  pos = 0;</span></span><br><span class="line">        buffer.flip();<span class="comment">//把这行注释掉后，下面的循环就是5次了。</span></span><br><span class="line">        <span class="comment">//在重置一次，pos为0，lim（可读写操作有效数据位数）为0，get会报错，也不让写。要写要clear</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 重置游标之后 ： java.nio.HeapByteBuffer[pos=0 lim=3 cap=8]</span></span><br><span class="line">        <span class="comment">// 游标为0， 限制为3， </span></span><br><span class="line">        System.out.println(<span class="string">"重置游标之后 ： "</span> + buffer);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 清空Buffer， pos = 0; lim = cap;</span></span><br><span class="line">        <span class="comment">// buffer.clear();</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// get() -&gt; 获取当前游标指向的位置的数据。</span></span><br><span class="line">        <span class="comment">// System.out.println(buffer.get());</span></span><br><span class="line">        <span class="comment">// remaining是lim-pos</span></span><br><span class="line">        <span class="comment">/*for(int i = 0; i &lt; buffer.remaining(); i++)&#123;</span></span><br><span class="line"><span class="comment">            // get(int index) -&gt; 获取指定位置的数据。</span></span><br><span class="line"><span class="comment">            int data = buffer.get(i);</span></span><br><span class="line"><span class="comment">            System.out.println(i + " - " + data);</span></span><br><span class="line"><span class="comment">        &#125;*/</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><strong>AIO</strong> <strong>编程</strong> <em>AsynchronousIO</em>： 异步非阻塞的编程方式 <ul>
<li>与 <em>NIO</em> 不同，当进行读写操作时，只须直接调用 <em>API</em> 的 <em>read</em> 或 <em>write</em> 方法即可。这两种 方法均为异步的，对于读操作而言，当有流可读取时，操作系统会将可读的流传入 <em>read</em> 方 法的缓冲区，并通知应用程序；对于写操作而言，当操作系统将 <em>write</em> 方法传递的流写入完 毕时，操作系统主动通知应用程序。即可以理解为，<em>read/write</em> 方法都是异步的，完成后会 主动调用回调函数。</li>
<li>客户端向服务端发数据，首先是OS接收到，他会将数据写到buffer里，然后通知应用程序代码，数据已经准备好了，可以read拿走了。应用代码write时，也会不数据同步进入OS的Buffer里，通过反向通知告诉应用程序已经写完了。buffer数据会自动地反回给client。client与server交互借助OS实现异步操作。</li>
<li>在 <em>JDK1.7</em> 中，这部分内容被称作 <em>NIO.2</em>，主要在 <em>java.nio.channels</em> 包下增加了下面四个异步通道： <ul>
<li><em>AsynchronousSocketChannel</em> </li>
<li><em>AsynchronousServerSocketChannel</em></li>
<li><em>AsynchronousFileChannel</em> </li>
<li><em>AsynchronousDatagramChannel</em> </li>
</ul>
</li>
<li>异步非阻塞，服务器实现模式为一个有效请求一个线程，客户端的 <em>I/O</em> 请求都是由 <em>OS</em> 先完成了再通知服务器应用去启动线程进行处理。 </li>
<li><em>AIO</em> 方式使用于连接数目多且连接比较长（重操作）的架构，比如相册服务器，充分调 用 <em>OS</em> 参与并发操作，编程比较复杂，<em>JDK7</em> 开始支持。 </li>
</ul>
</li>
</ul>
<p><img src="\media\AIO执行流程图.jpg" alt=""></p>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AIOServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 线程池， 提高服务端效率。</span></span><br><span class="line">    <span class="keyword">private</span> ExecutorService service;</span><br><span class="line">    <span class="comment">// 线程组</span></span><br><span class="line">    <span class="comment">// private AsynchronousChannelGroup group;</span></span><br><span class="line">    <span class="comment">// 服务端通道， 针对服务器端定义的通道。</span></span><br><span class="line">    <span class="keyword">private</span> AsynchronousServerSocketChannel serverChannel;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AIOServer</span><span class="params">(<span class="keyword">int</span> port)</span></span>&#123;</span><br><span class="line">        init(<span class="number">9999</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(<span class="keyword">int</span> port)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">"server starting at port : "</span> + port + <span class="string">" ..."</span>);</span><br><span class="line">            <span class="comment">// 定长线程池</span></span><br><span class="line">            service = Executors.newFixedThreadPool(<span class="number">4</span>);</span><br><span class="line">            <span class="comment">/* 使用线程组</span></span><br><span class="line"><span class="comment">            group = AsynchronousChannelGroup.withThreadPool(service);</span></span><br><span class="line"><span class="comment">            serverChannel = AsynchronousServerSocketChannel.open(group);</span></span><br><span class="line"><span class="comment">            */</span></span><br><span class="line">            <span class="comment">// 开启服务端通道， 通过静态方法创建的。</span></span><br><span class="line">            serverChannel = AsynchronousServerSocketChannel.open();</span><br><span class="line">            <span class="comment">// 绑定监听端口， 服务器启动成功，但是未监听请求。</span></span><br><span class="line">            serverChannel.bind(<span class="keyword">new</span> InetSocketAddress(port));</span><br><span class="line">            System.out.println(<span class="string">"server started."</span>);</span><br><span class="line">            <span class="comment">// 开始监听 </span></span><br><span class="line">            <span class="comment">// accept(T attachment, CompletionHandler&lt;AsynchronousSocketChannel, ? super T&gt;)</span></span><br><span class="line">            <span class="comment">// AIO开发中，监听是一个类似递归的监听操作。每次监听到客户端请求后，都需要处理逻辑开启下一次的监听。</span></span><br><span class="line">            <span class="comment">// 下一次的监听，需要服务器的资源继续支持。this传递到AIOServerHandler的completed方法中</span></span><br><span class="line">            serverChannel.accept(<span class="keyword">this</span>, <span class="keyword">new</span> AIOServerHandler());</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> AIOServer(<span class="number">9999</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ExecutorService <span class="title">getService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> service;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setService</span><span class="params">(ExecutorService service)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.service = service;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> AsynchronousServerSocketChannel <span class="title">getServerChannel</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> serverChannel;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setServerChannel</span><span class="params">(AsynchronousServerSocketChannel serverChannel)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.serverChannel = serverChannel;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>AIOServerHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AIOServerHandler</span> <span class="keyword">implements</span> <span class="title">CompletionHandler</span>&lt;<span class="title">AsynchronousSocketChannel</span>, <span class="title">AIOServer</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 业务处理逻辑， 当请求到来后，监听成功，应该做什么。</span></span><br><span class="line"><span class="comment">     * 一定要实现的逻辑： 为下一次客户端请求开启监听。accept方法调用。</span></span><br><span class="line"><span class="comment">     * result参数 ： 就是和客户端直接建立关联的通道。</span></span><br><span class="line"><span class="comment">     *  无论BIO、NIO、AIO中，一旦连接建立，两端是平等的。</span></span><br><span class="line"><span class="comment">     *  result中有通道中的所有相关数据。如：OS操作系统准备好的读取数据缓存，或等待返回数据的缓存。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">completed</span><span class="params">(AsynchronousSocketChannel result, AIOServer attachment)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 处理下一次的客户端请求。类似递归逻辑。</span></span><br><span class="line">        attachment.getServerChannel().accept(attachment, <span class="keyword">this</span>);</span><br><span class="line">        doRead(result);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 异常处理逻辑， 当服务端代码出现异常的时候，做什么事情。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">failed</span><span class="params">(Throwable exc, AIOServer attachment)</span> </span>&#123;</span><br><span class="line">        exc.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 真实项目中，服务器返回的结果应该是根据客户端的请求数据计算得到的。不是等待控制台输入的。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> result</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doWrite</span><span class="params">(AsynchronousSocketChannel result)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            ByteBuffer buffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line">            System.out.print(<span class="string">"enter message send to client &gt; "</span>);</span><br><span class="line">            Scanner s = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">            String line = s.nextLine();</span><br><span class="line">            buffer.put(line.getBytes(<span class="string">"UTF-8"</span>));</span><br><span class="line">            <span class="comment">// 重点：必须复位，必须复位，必须复位</span></span><br><span class="line">            buffer.flip();</span><br><span class="line">            <span class="comment">// write方法是一个异步操作。具体实现由OS实现。 可以增加get方法，实现阻塞，等待OS的写操作结束。</span></span><br><span class="line">            result.write(buffer);</span><br><span class="line">            <span class="comment">// result.write(buffer).get(); // 调用get代表服务端线程阻塞，等待写操作完成</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (UnsupportedEncodingException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="comment">/* catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">            e.printStackTrace();</span></span><br><span class="line"><span class="comment">        &#125; catch (ExecutionException e) &#123;</span></span><br><span class="line"><span class="comment">            e.printStackTrace();</span></span><br><span class="line"><span class="comment">        &#125;*/</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doRead</span><span class="params">(<span class="keyword">final</span> AsynchronousSocketChannel channel)</span></span>&#123;</span><br><span class="line">        ByteBuffer buffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * 异步读操作， read(Buffer destination, A attachment, </span></span><br><span class="line"><span class="comment">         *                    CompletionHandler&lt;Integer, ? super A&gt; handler)</span></span><br><span class="line"><span class="comment">         * destination - 目的地， 是处理客户端传递数据的中转缓存。 可以不使用。</span></span><br><span class="line"><span class="comment">         * attachment - 处理客户端传递数据的对象。 通常使用Buffer处理。</span></span><br><span class="line"><span class="comment">         * handler - 处理逻辑</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        channel.read(buffer, buffer, <span class="keyword">new</span> CompletionHandler&lt;Integer, ByteBuffer&gt;() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">/**</span></span><br><span class="line"><span class="comment">             * 业务逻辑，读取客户端传输数据</span></span><br><span class="line"><span class="comment">             * attachment - 在completed方法执行的时候，OS已经将客户端请求的数据写入到Buffer中了。</span></span><br><span class="line"><span class="comment">             *  但是未复位（flip）。 使用前一定要复位。</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">completed</span><span class="params">(Integer result, ByteBuffer attachment)</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    System.out.println(attachment.capacity());</span><br><span class="line">                    <span class="comment">// 复位</span></span><br><span class="line">                    attachment.flip();</span><br><span class="line">                    System.out.println(<span class="string">"from client : "</span> + <span class="keyword">new</span> String(attachment.array(), <span class="string">"UTF-8"</span>));</span><br><span class="line">                    doWrite(channel);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (UnsupportedEncodingException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">failed</span><span class="params">(Throwable exc, ByteBuffer attachment)</span> </span>&#123;</span><br><span class="line">                exc.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>client</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AIOClient</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> AsynchronousSocketChannel channel;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AIOClient</span><span class="params">(String host, <span class="keyword">int</span> port)</span></span>&#123;</span><br><span class="line">        init(host, port);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(String host, <span class="keyword">int</span> port)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 开启通道</span></span><br><span class="line">            channel = AsynchronousSocketChannel.open();</span><br><span class="line">            <span class="comment">// 发起请求，建立连接。</span></span><br><span class="line">            channel.connect(<span class="keyword">new</span> InetSocketAddress(host, port));</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(String line)</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            ByteBuffer buffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line">            buffer.put(line.getBytes(<span class="string">"UTF-8"</span>));</span><br><span class="line">            buffer.flip();</span><br><span class="line">            channel.write(buffer);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (UnsupportedEncodingException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span></span>&#123;</span><br><span class="line">        ByteBuffer buffer = ByteBuffer.allocate(<span class="number">1024</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// read方法是异步方法，OS实现的。get方法是一个阻塞方法，会等待OS处理结束后再返回，要不代码不等待，下面没数据打印出来。真实开发可以不加，其结果依靠OS自己去等待，拿到数据再返回通知，</span></span><br><span class="line">            channel.read(buffer).get();</span><br><span class="line">            <span class="comment">// channel.read(dst, attachment, handler);</span></span><br><span class="line">            buffer.flip();</span><br><span class="line">            System.out.println(<span class="string">"from server : "</span> + <span class="keyword">new</span> String(buffer.array(), <span class="string">"UTF-8"</span>));</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (ExecutionException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (UnsupportedEncodingException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doDestory</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> != channel)&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                channel.close();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        AIOClient client = <span class="keyword">new</span> AIOClient(<span class="string">"localhost"</span>, <span class="number">9999</span>);</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            System.out.print(<span class="string">"enter message send to server &gt; "</span>);</span><br><span class="line">            Scanner s = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">            String line = s.nextLine();</span><br><span class="line">            client.write(line);</span><br><span class="line">            client.read();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            client.doDestory();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="合体后期（Netty）"><a href="#合体后期（Netty）" class="headerlink" title="合体后期（Netty）"></a>合体后期（Netty）</h3><ul>
<li><p><strong>简介</strong> </p>
<p>​        <em>Netty</em> 是由 <em>JBOSS</em> 提供的一个 <em>java</em> 开源框架。<em>Netty</em> 提供异步的、事件驱动的网络应用 程序框架和工具，用以快速开发高性能、高可靠性的网络服务器和客户端程序。 它是建立再NIO和AIO基础之上的。</p>
<p>​        也就是说，<em>Netty</em> 是一个基于 <em>NIO</em> 的客户、服务器端编程框架，使用 <em>Netty</em> 可以确保你 快速和简单的开发出一个网络应用，例如实现了某种协议的客户，服务端应用。<em>Netty</em> 相当 简化和流线化了网络应用的编程开发过程，例如，<em>TCP</em> 和 <em>UDP</em> 的 <em>socket</em> 服务开发。</p>
<p>​        “<em>快速</em>”<em>和</em>“<em>简单</em>”<em>并不用产生维护性或性能上的问题。</em>Netty<em> 是一个吸收了多种协议的实 现经验，这些协议包括 </em>FTP,SMTP,HTTP<em>，各种二进制，文本协议，并经过相当精心设计的项 目，最终，</em>Netty* 成功的找到了一种方式，在保证易于开发的同时还保证了其应用的性能， 稳定性和伸缩性。 </p>
<p>​        <em>Netty</em> 从 <em>4.x</em> 版本开始，需要使用 <em>JDK1.6</em> 及以上版本提供基础支撑。 </p>
<p>​        在设计上：针对多种传输类型的统一接口 <em>-</em> 阻塞和非阻塞；简单但更强大的线程模型； 真正的无连接的数据报套接字支持；链接逻辑支持复用； </p>
<p>​        在性能上：比核心 <em>Java API</em> 更好的吞吐量，较低的延时；资源消耗更少，这个得益于 共享池和重用；减少内存拷贝 </p>
<p>​        在健壮性上：消除由于慢，快，或重载连接产生的 <em>OutOfMemoryError</em>；消除经常发现 在 <em>NIO</em> 在高速网络中的应用中的不公平的读<em>/</em>写比 </p>
<p>​        在安全上：完整的 <em>SSL / TLS</em> 和 <em>StartTLS</em> 的支持 </p>
<p>​        且已得到大量商业应用的真实验证<em>,</em>如：<em>Hadoop</em> 项目的 <em>Avro</em>（<em>RPC</em> 框架）、<em>Dubbo</em>、<em>Dubbox</em>等 <em>RPC</em> 框架。 </p>
<p>​        <em>Netty</em> 的官网是：<em><span class="exturl" data-url="aHR0cDovL25ldHR5Lmlv" title="http://netty.io">http://netty.io<i class="fa fa-external-link"></i></span></em> </p>
<p>​        有 三 方 提 供 的 中 文 翻 译 <em>Netty</em> 用 户 手 册 （ 官 网 提 供 源 信 息 ）： <em><span class="exturl" data-url="aHR0cDovL2lmZXZlLmNvbS9uZXR0eTUtdXNlci1ndWlkZS8=" title="http://ifeve.com/netty5-user-guide/">http://ifeve.com/netty5-user-guide/<i class="fa fa-external-link"></i></span></em></p>
</li>
<li><p><strong>Netty</strong> <strong>架构</strong></p>
<p><img src="\media\Netty架构.jpg" alt=""></p>
</li>
<li><p>线程模型（acceptor是一个监听线程）</p>
<p><img src="\media\1582184953(1" alt="">.jpg)</p>
<ul>
<li><p><strong>单线程模型</strong> </p>
<p>​        在 <em>ServerBootstrap</em> 调用方法 <em>group</em> 的时候，传递的参数是同一个线程组，且在构造线程 组的时候，构造参数为 <em>1</em>，这种开发方式，就是一个单线程模型。 个人机开发测试使用。不推荐。</p>
<p>​        在处理acceptor和runnable task的线程组合并成一个，并且只有一个线程。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 初始化线程组,构建线程组的时候，如果不传递参数，则默认构建的线程组线程数是CPU核心数量。</span><br><span class="line">acceptorGroup = new NioEventLoopGroup(1);</span><br><span class="line">// 初始化服务的配置</span><br><span class="line">bootstrap = new ServerBootstrap();</span><br><span class="line">// 绑定线程组</span><br><span class="line">bootstrap.group(acceptorGroup, acceptorGroup);</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
<li><p><strong>多线程模型</strong> </p>
<p>​        在 <em>ServerBootstrap</em> 调用方法 <em>group</em> 的时候，传递的参数是两个不同的线程组。负责监听 的 <em>acceptor</em> 线程组，线程数为 <em>1</em>，也就是构造参数为 <em>1</em>。负责处理客户端任务的线程组，线 程数大于 <em>1</em>，也就是构造参数大于 <em>1</em>。这种开发方式，就是多线程模型。 </p>
<p>​        长连接，且客户端数量较少，连接持续时间较长情况下使用。如：企业内部交流应用。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">// 初始化线程组,构建线程组的时候，如果不传递参数，则默认构建的线程组线程数是CPU核心数量。</span><br><span class="line">acceptorGroup = new NioEventLoopGroup(1);</span><br><span class="line">clientGroup = new NioEventLoopGroup(&gt;1);</span><br><span class="line">// 初始化服务的配置</span><br><span class="line">bootstrap = new ServerBootstrap();</span><br><span class="line">// 绑定线程组</span><br><span class="line">bootstrap.group(acceptorGroup, clientGroup);</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>主从多线程模型</strong> </p>
<p>​        在 <em>ServerBootstrap</em> 调用方法 <em>group</em> 的时候，传递的参数是两个不同的线程组。负责监听 的 <em>acceptor</em> 线程组，线程数大于 <em>1</em>，也就是构造参数大于 <em>1</em>。负责处理客户端任务的线程组， 线程数大于 <em>1</em>，也就是构造参数大于 <em>1</em>。这种开发方式，就是主从多线程模型。 </p>
<p>​        长连接，客户端数量相对较多，连接持续时间比较长的情况下使用。如：对外提供服务 </p>
<p>的相册服务器。 </p>
</li>
</ul>
<p>案例：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.netty<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>netty-all<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.0.0.Alpha2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- &lt;version&gt;4.1.24.Final&lt;/version&gt; --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.netty<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>netty-codec-http<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.0.0.Alpha2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- &lt;version&gt;4.1.24.Final&lt;/version&gt; --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 接收处理工具 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.jboss.marshalling<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jboss-marshalling-river<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.4.11.Final<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 序列化处理工具 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.jboss.marshalling<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jboss-marshalling-serial<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.4.11.Final<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 系统信息收集 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.hyperic.sigar<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>com.springsource.org.hyperic.sigar<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.6.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.kaazing<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>sigar.dist<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">classifier</span>&gt;</span>distribution<span class="tag">&lt;/<span class="name">classifier</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">type</span>&gt;</span>zip<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>工具类</p>
<p>GzipUtils</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GzipUtils</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        FileInputStream fis = <span class="keyword">new</span> FileInputStream(<span class="string">"D:\\3\\1.jpg"</span>);</span><br><span class="line">        <span class="keyword">byte</span>[] temp = <span class="keyword">new</span> <span class="keyword">byte</span>[fis.available()];</span><br><span class="line">        <span class="keyword">int</span> length = fis.read(temp);</span><br><span class="line">        System.out.println(<span class="string">"长度 : "</span> + length);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">byte</span>[] zipArray = GzipUtils.zip(temp);</span><br><span class="line">        System.out.println(<span class="string">"压缩后的长度 : "</span> + zipArray.length);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">byte</span>[] unzipArray = GzipUtils.unzip(zipArray);</span><br><span class="line">        System.out.println(<span class="string">"解压缩后的长度 : "</span> + unzipArray.length);</span><br><span class="line"></span><br><span class="line">        FileOutputStream fos = <span class="keyword">new</span> FileOutputStream(<span class="string">"D:\\3\\101.jpg"</span>);</span><br><span class="line">        fos.write(unzipArray);</span><br><span class="line">        fos.flush();</span><br><span class="line"></span><br><span class="line">        fos.close();</span><br><span class="line">        fis.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 解压缩</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> source 源数据。需要解压的数据。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 解压后的数据。 恢复的数据。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">byte</span>[] unzip(<span class="keyword">byte</span>[] source) <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        ByteArrayOutputStream out = <span class="keyword">new</span> ByteArrayOutputStream();</span><br><span class="line">        ByteArrayInputStream in = <span class="keyword">new</span> ByteArrayInputStream(source);</span><br><span class="line">        <span class="comment">// JDK提供的。 专门用于压缩使用的流对象。可以处理字节数组数据。</span></span><br><span class="line">        GZIPInputStream zipIn = <span class="keyword">new</span> GZIPInputStream(in);</span><br><span class="line">        <span class="keyword">byte</span>[] temp = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">256</span>];</span><br><span class="line">        <span class="keyword">int</span> length = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>((length = zipIn.read(temp, <span class="number">0</span>, temp.length)) != -<span class="number">1</span>)&#123;</span><br><span class="line">            out.write(temp, <span class="number">0</span>, length);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 将字节数组输出流中的数据，转换为一个字节数组。</span></span><br><span class="line">        <span class="keyword">byte</span>[] target = out.toByteArray();</span><br><span class="line"></span><br><span class="line">        zipIn.close();</span><br><span class="line">        out.close();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 压缩</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> source 源数据，需要压缩的数据</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 压缩后的数据。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">byte</span>[] zip(<span class="keyword">byte</span>[] source) <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        ByteArrayOutputStream out = <span class="keyword">new</span> ByteArrayOutputStream();</span><br><span class="line">        <span class="comment">// 输出流，JDK提供的，提供解压缩功能。</span></span><br><span class="line">        GZIPOutputStream zipOut = <span class="keyword">new</span> GZIPOutputStream(out);</span><br><span class="line">        <span class="comment">// 将压缩信息写入到内存。 写入的过程会实现解压。</span></span><br><span class="line">        zipOut.write(source);</span><br><span class="line">        <span class="comment">// 结束。</span></span><br><span class="line">        zipOut.finish();</span><br><span class="line">        <span class="keyword">byte</span>[] target = out.toByteArray();</span><br><span class="line"></span><br><span class="line">        zipOut.close();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>OSUtils</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OSUtils</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// System信息，从jvm获取</span></span><br><span class="line">            property();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// cpu信息</span></span><br><span class="line">            cpu();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// 内存信息</span></span><br><span class="line">            memory();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// 操作系统信息</span></span><br><span class="line">            os();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// 用户信息</span></span><br><span class="line">            who();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// 文件系统信息</span></span><br><span class="line">            file();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// 网络信息</span></span><br><span class="line">            net();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">            <span class="comment">// 以太网信息</span></span><br><span class="line">            ethernet();</span><br><span class="line">            System.out.println(<span class="string">"----------------------------------"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e1) &#123;</span><br><span class="line">            e1.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">property</span><span class="params">()</span> <span class="keyword">throws</span> UnknownHostException </span>&#123;</span><br><span class="line">        Runtime r = Runtime.getRuntime();</span><br><span class="line">        Properties props = System.getProperties();</span><br><span class="line">        InetAddress addr;</span><br><span class="line">        addr = InetAddress.getLocalHost();</span><br><span class="line">        String ip = addr.getHostAddress();</span><br><span class="line">        Map&lt;String, String&gt; map = System.getenv();</span><br><span class="line">        String userName = map.get(<span class="string">"USERNAME"</span>);<span class="comment">// 获取用户名</span></span><br><span class="line">        String computerName = map.get(<span class="string">"COMPUTERNAME"</span>);<span class="comment">// 获取计算机名</span></span><br><span class="line">        String userDomain = map.get(<span class="string">"USERDOMAIN"</span>);<span class="comment">// 获取计算机域名</span></span><br><span class="line">        System.out.println(<span class="string">"用户名:    "</span> + userName);</span><br><span class="line">        System.out.println(<span class="string">"计算机名:    "</span> + computerName);</span><br><span class="line">        System.out.println(<span class="string">"计算机域名:    "</span> + userDomain);</span><br><span class="line">        System.out.println(<span class="string">"本地ip地址:    "</span> + ip);</span><br><span class="line">        System.out.println(<span class="string">"本地主机名:    "</span> + addr.getHostName());</span><br><span class="line">        System.out.println(<span class="string">"JVM可以使用的总内存:    "</span> + r.totalMemory());</span><br><span class="line">        System.out.println(<span class="string">"JVM可以使用的剩余内存:    "</span> + r.freeMemory());</span><br><span class="line">        System.out.println(<span class="string">"JVM可以使用的处理器个数:    "</span> + r.availableProcessors());</span><br><span class="line">        System.out.println(<span class="string">"Java的运行环境版本：    "</span> + props.getProperty(<span class="string">"java.version"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的运行环境供应商：    "</span> + props.getProperty(<span class="string">"java.vendor"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java供应商的URL：    "</span> + props.getProperty(<span class="string">"java.vendor.url"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的安装路径：    "</span> + props.getProperty(<span class="string">"java.home"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的虚拟机规范版本：    "</span> + props.getProperty(<span class="string">"java.vm.specification.version"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的虚拟机规范供应商：    "</span> + props.getProperty(<span class="string">"java.vm.specification.vendor"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的虚拟机规范名称：    "</span> + props.getProperty(<span class="string">"java.vm.specification.name"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的虚拟机实现版本：    "</span> + props.getProperty(<span class="string">"java.vm.version"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的虚拟机实现供应商：    "</span> + props.getProperty(<span class="string">"java.vm.vendor"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的虚拟机实现名称：    "</span> + props.getProperty(<span class="string">"java.vm.name"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java运行时环境规范版本：    "</span> + props.getProperty(<span class="string">"java.specification.version"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java运行时环境规范供应商：    "</span> + props.getProperty(<span class="string">"java.specification.vender"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java运行时环境规范名称：    "</span> + props.getProperty(<span class="string">"java.specification.name"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的类格式版本号：    "</span> + props.getProperty(<span class="string">"java.class.version"</span>));</span><br><span class="line">        System.out.println(<span class="string">"Java的类路径：    "</span> + props.getProperty(<span class="string">"java.class.path"</span>));</span><br><span class="line">        System.out.println(<span class="string">"加载库时搜索的路径列表：    "</span> + props.getProperty(<span class="string">"java.library.path"</span>));</span><br><span class="line">        System.out.println(<span class="string">"默认的临时文件路径：    "</span> + props.getProperty(<span class="string">"java.io.tmpdir"</span>));</span><br><span class="line">        System.out.println(<span class="string">"一个或多个扩展目录的路径：    "</span> + props.getProperty(<span class="string">"java.ext.dirs"</span>));</span><br><span class="line">        System.out.println(<span class="string">"操作系统的名称：    "</span> + props.getProperty(<span class="string">"os.name"</span>));</span><br><span class="line">        System.out.println(<span class="string">"操作系统的构架：    "</span> + props.getProperty(<span class="string">"os.arch"</span>));</span><br><span class="line">        System.out.println(<span class="string">"操作系统的版本：    "</span> + props.getProperty(<span class="string">"os.version"</span>));</span><br><span class="line">        System.out.println(<span class="string">"文件分隔符：    "</span> + props.getProperty(<span class="string">"file.separator"</span>));</span><br><span class="line">        System.out.println(<span class="string">"路径分隔符：    "</span> + props.getProperty(<span class="string">"path.separator"</span>));</span><br><span class="line">        System.out.println(<span class="string">"行分隔符：    "</span> + props.getProperty(<span class="string">"line.separator"</span>));</span><br><span class="line">        System.out.println(<span class="string">"用户的账户名称：    "</span> + props.getProperty(<span class="string">"user.name"</span>));</span><br><span class="line">        System.out.println(<span class="string">"用户的主目录：    "</span> + props.getProperty(<span class="string">"user.home"</span>));</span><br><span class="line">        System.out.println(<span class="string">"用户的当前工作目录：    "</span> + props.getProperty(<span class="string">"user.dir"</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">memory</span><span class="params">()</span> <span class="keyword">throws</span> SigarException </span>&#123;</span><br><span class="line">        Sigar sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">        Mem mem = sigar.getMem();</span><br><span class="line">        <span class="comment">// 内存总量</span></span><br><span class="line">        System.out.println(<span class="string">"内存总量:    "</span> + mem.getTotal() / <span class="number">1024L</span> + <span class="string">"K av"</span>);</span><br><span class="line">        <span class="comment">// 当前内存使用量</span></span><br><span class="line">        System.out.println(<span class="string">"当前内存使用量:    "</span> + mem.getUsed() / <span class="number">1024L</span> + <span class="string">"K used"</span>);</span><br><span class="line">        <span class="comment">// 当前内存剩余量</span></span><br><span class="line">        System.out.println(<span class="string">"当前内存剩余量:    "</span> + mem.getFree() / <span class="number">1024L</span> + <span class="string">"K free"</span>);</span><br><span class="line">        Swap swap = sigar.getSwap();</span><br><span class="line">        <span class="comment">// 交换区总量</span></span><br><span class="line">        System.out.println(<span class="string">"交换区总量:    "</span> + swap.getTotal() / <span class="number">1024L</span> + <span class="string">"K av"</span>);</span><br><span class="line">        <span class="comment">// 当前交换区使用量</span></span><br><span class="line">        System.out.println(<span class="string">"当前交换区使用量:    "</span> + swap.getUsed() / <span class="number">1024L</span> + <span class="string">"K used"</span>);</span><br><span class="line">        <span class="comment">// 当前交换区剩余量</span></span><br><span class="line">        System.out.println(<span class="string">"当前交换区剩余量:    "</span> + swap.getFree() / <span class="number">1024L</span> + <span class="string">"K free"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">cpu</span><span class="params">()</span> <span class="keyword">throws</span> SigarException </span>&#123;</span><br><span class="line">        Sigar sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">        CpuInfo infos[] = sigar.getCpuInfoList();</span><br><span class="line">        CpuPerc cpuList[] = <span class="keyword">null</span>;</span><br><span class="line">        cpuList = sigar.getCpuPercList();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; infos.length; i++) &#123;<span class="comment">// 不管是单块CPU还是多CPU都适用</span></span><br><span class="line">            CpuInfo info = infos[i];</span><br><span class="line">            System.out.println(<span class="string">"第"</span> + (i + <span class="number">1</span>) + <span class="string">"块CPU信息"</span>);</span><br><span class="line">            System.out.println(<span class="string">"CPU的总量MHz:    "</span> + info.getMhz());<span class="comment">// CPU的总量MHz</span></span><br><span class="line">            System.out.println(<span class="string">"CPU生产商:    "</span> + info.getVendor());<span class="comment">// 获得CPU的卖主，如：Intel</span></span><br><span class="line">            System.out.println(<span class="string">"CPU类别:    "</span> + info.getModel());<span class="comment">// 获得CPU的类别，如：Celeron</span></span><br><span class="line">            System.out.println(<span class="string">"CPU缓存数量:    "</span> + info.getCacheSize());<span class="comment">// 缓冲存储器数量</span></span><br><span class="line">            printCpuPerc(cpuList[i]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printCpuPerc</span><span class="params">(CpuPerc cpu)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"CPU用户使用率:    "</span> + CpuPerc.format(cpu.getUser()));<span class="comment">// 用户使用率</span></span><br><span class="line">        System.out.println(<span class="string">"CPU系统使用率:    "</span> + CpuPerc.format(cpu.getSys()));<span class="comment">// 系统使用率</span></span><br><span class="line">        System.out.println(<span class="string">"CPU当前等待率:    "</span> + CpuPerc.format(cpu.getWait()));<span class="comment">// 当前等待率</span></span><br><span class="line">        System.out.println(<span class="string">"CPU当前错误率:    "</span> + CpuPerc.format(cpu.getNice()));<span class="comment">//</span></span><br><span class="line">        System.out.println(<span class="string">"CPU当前空闲率:    "</span> + CpuPerc.format(cpu.getIdle()));<span class="comment">// 当前空闲率</span></span><br><span class="line">        System.out.println(<span class="string">"CPU总的使用率:    "</span> + CpuPerc.format(cpu.getCombined()));<span class="comment">// 总的使用率</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">os</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        OperatingSystem OS = OperatingSystem.getInstance();</span><br><span class="line">        <span class="comment">// 操作系统内核类型如： 386、486、586等x86</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统:    "</span> + OS.getArch());</span><br><span class="line">        System.out.println(<span class="string">"操作系统CpuEndian():    "</span> + OS.getCpuEndian());<span class="comment">//</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统DataModel():    "</span> + OS.getDataModel());<span class="comment">//</span></span><br><span class="line">        <span class="comment">// 系统描述</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统的描述:    "</span> + OS.getDescription());</span><br><span class="line">        <span class="comment">// 操作系统类型</span></span><br><span class="line">        <span class="comment">// System.out.println("OS.getName():    " + OS.getName());</span></span><br><span class="line">        <span class="comment">// System.out.println("OS.getPatchLevel():    " + OS.getPatchLevel());//</span></span><br><span class="line">        <span class="comment">// 操作系统的卖主</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统的卖主:    "</span> + OS.getVendor());</span><br><span class="line">        <span class="comment">// 卖主名称</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统的卖主名:    "</span> + OS.getVendorCodeName());</span><br><span class="line">        <span class="comment">// 操作系统名称</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统名称:    "</span> + OS.getVendorName());</span><br><span class="line">        <span class="comment">// 操作系统卖主类型</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统卖主类型:    "</span> + OS.getVendorVersion());</span><br><span class="line">        <span class="comment">// 操作系统的版本号</span></span><br><span class="line">        System.out.println(<span class="string">"操作系统的版本号:    "</span> + OS.getVersion());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">who</span><span class="params">()</span> <span class="keyword">throws</span> SigarException </span>&#123;</span><br><span class="line">        Sigar sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">        Who who[] = sigar.getWhoList();</span><br><span class="line">        <span class="keyword">if</span> (who != <span class="keyword">null</span> &amp;&amp; who.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; who.length; i++) &#123;</span><br><span class="line">                <span class="comment">// System.out.println("当前系统进程表中的用户名" + String.valueOf(i));</span></span><br><span class="line">                Who _who = who[i];</span><br><span class="line">                System.out.println(<span class="string">"用户控制台:    "</span> + _who.getDevice());</span><br><span class="line">                System.out.println(<span class="string">"用户host:    "</span> + _who.getHost());</span><br><span class="line">                <span class="comment">// System.out.println("getTime():    " + _who.getTime());</span></span><br><span class="line">                <span class="comment">// 当前系统进程表中的用户名</span></span><br><span class="line">                System.out.println(<span class="string">"当前系统进程表中的用户名:    "</span> + _who.getUser());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">file</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        Sigar sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">        FileSystem fslist[] = sigar.getFileSystemList();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; fslist.length; i++) &#123;</span><br><span class="line">                System.out.println(<span class="string">"分区的盘符名称"</span> + i);</span><br><span class="line">                FileSystem fs = fslist[i];</span><br><span class="line">                <span class="comment">// 分区的盘符名称</span></span><br><span class="line">                System.out.println(<span class="string">"盘符名称:    "</span> + fs.getDevName());</span><br><span class="line">                <span class="comment">// 分区的盘符名称</span></span><br><span class="line">                System.out.println(<span class="string">"盘符路径:    "</span> + fs.getDirName());</span><br><span class="line">                System.out.println(<span class="string">"盘符标志:    "</span> + fs.getFlags());<span class="comment">//</span></span><br><span class="line">                <span class="comment">// 文件系统类型，比如 FAT32、NTFS</span></span><br><span class="line">                System.out.println(<span class="string">"盘符类型:    "</span> + fs.getSysTypeName());</span><br><span class="line">                <span class="comment">// 文件系统类型名，比如本地硬盘、光驱、网络文件系统等</span></span><br><span class="line">                System.out.println(<span class="string">"盘符类型名:    "</span> + fs.getTypeName());</span><br><span class="line">                <span class="comment">// 文件系统类型</span></span><br><span class="line">                System.out.println(<span class="string">"盘符文件系统类型:    "</span> + fs.getType());</span><br><span class="line">                FileSystemUsage usage = <span class="keyword">null</span>;</span><br><span class="line">                usage = sigar.getFileSystemUsage(fs.getDirName());</span><br><span class="line">                <span class="keyword">switch</span> (fs.getType()) &#123;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">0</span>: <span class="comment">// TYPE_UNKNOWN ：未知</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// TYPE_NONE</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">2</span>: <span class="comment">// TYPE_LOCAL_DISK : 本地硬盘</span></span><br><span class="line">                        <span class="comment">// 文件系统总大小</span></span><br><span class="line">                        System.out.println(fs.getDevName() + <span class="string">"总大小:    "</span> + usage.getTotal() + <span class="string">"KB"</span>);</span><br><span class="line">                        <span class="comment">// 文件系统剩余大小</span></span><br><span class="line">                        System.out.println(fs.getDevName() + <span class="string">"剩余大小:    "</span> + usage.getFree() + <span class="string">"KB"</span>);</span><br><span class="line">                        <span class="comment">// 文件系统可用大小</span></span><br><span class="line">                        System.out.println(fs.getDevName() + <span class="string">"可用大小:    "</span> + usage.getAvail() + <span class="string">"KB"</span>);</span><br><span class="line">                        <span class="comment">// 文件系统已经使用量</span></span><br><span class="line">                        System.out.println(fs.getDevName() + <span class="string">"已经使用量:    "</span> + usage.getUsed() + <span class="string">"KB"</span>);</span><br><span class="line">                        <span class="keyword">double</span> usePercent = usage.getUsePercent() * <span class="number">100</span>D;</span><br><span class="line">                        <span class="comment">// 文件系统资源的利用率</span></span><br><span class="line">                        System.out.println(fs.getDevName() + <span class="string">"资源的利用率:    "</span> + usePercent + <span class="string">"%"</span>);</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">3</span>:<span class="comment">// TYPE_NETWORK ：网络</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">4</span>:<span class="comment">// TYPE_RAM_DISK ：闪存</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">5</span>:<span class="comment">// TYPE_CDROM ：光驱</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    <span class="keyword">case</span> <span class="number">6</span>:<span class="comment">// TYPE_SWAP ：页面交换</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(fs.getDevName() + <span class="string">"读出：    "</span> + usage.getDiskReads());</span><br><span class="line">                System.out.println(fs.getDevName() + <span class="string">"写入：    "</span> + usage.getDiskWrites());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="comment">// <span class="doctag">TODO:</span> handle exception</span></span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">net</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        Sigar sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">        String ifNames[] = sigar.getNetInterfaceList();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; ifNames.length; i++) &#123;</span><br><span class="line">            String name = ifNames[i];</span><br><span class="line">            NetInterfaceConfig ifconfig = sigar.getNetInterfaceConfig(name);</span><br><span class="line">            System.out.println(<span class="string">"网络设备名:    "</span> + name);<span class="comment">// 网络设备名</span></span><br><span class="line">            System.out.println(<span class="string">"IP地址:    "</span> + ifconfig.getAddress());<span class="comment">// IP地址</span></span><br><span class="line">            System.out.println(<span class="string">"子网掩码:    "</span> + ifconfig.getNetmask());<span class="comment">// 子网掩码</span></span><br><span class="line">            <span class="keyword">if</span> ((ifconfig.getFlags() &amp; <span class="number">1L</span>) &lt;= <span class="number">0L</span>) &#123;</span><br><span class="line">                System.out.println(<span class="string">"!IFF_UP...skipping getNetInterfaceStat"</span>);</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            NetInterfaceStat ifstat = sigar.getNetInterfaceStat(name);</span><br><span class="line">            System.out.println(name + <span class="string">"接收的总包裹数:"</span> + ifstat.getRxPackets());<span class="comment">// 接收的总包裹数</span></span><br><span class="line">            System.out.println(name + <span class="string">"发送的总包裹数:"</span> + ifstat.getTxPackets());<span class="comment">// 发送的总包裹数</span></span><br><span class="line">            System.out.println(name + <span class="string">"接收到的总字节数:"</span> + ifstat.getRxBytes());<span class="comment">// 接收到的总字节数</span></span><br><span class="line">            System.out.println(name + <span class="string">"发送的总字节数:"</span> + ifstat.getTxBytes());<span class="comment">// 发送的总字节数</span></span><br><span class="line">            System.out.println(name + <span class="string">"接收到的错误包数:"</span> + ifstat.getRxErrors());<span class="comment">// 接收到的错误包数</span></span><br><span class="line">            System.out.println(name + <span class="string">"发送数据包时的错误数:"</span> + ifstat.getTxErrors());<span class="comment">// 发送数据包时的错误数</span></span><br><span class="line">            System.out.println(name + <span class="string">"接收时丢弃的包数:"</span> + ifstat.getRxDropped());<span class="comment">// 接收时丢弃的包数</span></span><br><span class="line">            System.out.println(name + <span class="string">"发送时丢弃的包数:"</span> + ifstat.getTxDropped());<span class="comment">// 发送时丢弃的包数</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">ethernet</span><span class="params">()</span> <span class="keyword">throws</span> SigarException </span>&#123;</span><br><span class="line">        Sigar sigar = <span class="keyword">null</span>;</span><br><span class="line">        sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">        String[] ifaces = sigar.getNetInterfaceList();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; ifaces.length; i++) &#123;</span><br><span class="line">            NetInterfaceConfig cfg = sigar.getNetInterfaceConfig(ifaces[i]);</span><br><span class="line">            <span class="keyword">if</span> (NetFlags.LOOPBACK_ADDRESS.equals(cfg.getAddress()) || (cfg.getFlags() &amp; NetFlags.IFF_LOOPBACK) != <span class="number">0</span></span><br><span class="line">                    || NetFlags.NULL_HWADDR.equals(cfg.getHwaddr())) &#123;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(cfg.getName() + <span class="string">"IP地址:"</span> + cfg.getAddress());<span class="comment">// IP地址</span></span><br><span class="line">            System.out.println(cfg.getName() + <span class="string">"网关广播地址:"</span> + cfg.getBroadcast());<span class="comment">// 网关广播地址</span></span><br><span class="line">            System.out.println(cfg.getName() + <span class="string">"网卡MAC地址:"</span> + cfg.getHwaddr());<span class="comment">// 网卡MAC地址</span></span><br><span class="line">            System.out.println(cfg.getName() + <span class="string">"子网掩码:"</span> + cfg.getNetmask());<span class="comment">// 子网掩码</span></span><br><span class="line">            System.out.println(cfg.getName() + <span class="string">"网卡描述信息:"</span> + cfg.getDescription());<span class="comment">// 网卡描述信息</span></span><br><span class="line">            System.out.println(cfg.getName() + <span class="string">"网卡类型"</span> + cfg.getType());<span class="comment">//</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>SerializableFactory4Marshalling</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SerializableFactory4Marshalling</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">     <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建Jboss Marshalling解码器MarshallingDecoder</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> MarshallingDecoder</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> MarshallingDecoder <span class="title">buildMarshallingDecoder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。</span></span><br><span class="line">        <span class="comment">//jboss-marshalling-serial 包提供</span></span><br><span class="line">        <span class="keyword">final</span> MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory(<span class="string">"serial"</span>);</span><br><span class="line">        <span class="comment">//创建了MarshallingConfiguration对象，配置了版本号为5 </span></span><br><span class="line">        <span class="keyword">final</span> MarshallingConfiguration configuration = <span class="keyword">new</span> MarshallingConfiguration();</span><br><span class="line">        <span class="comment">// 序列化版本。只要使用JDK5以上版本，version只能定义为5。</span></span><br><span class="line">        configuration.setVersion(<span class="number">5</span>);</span><br><span class="line">        <span class="comment">//根据marshallerFactory和configuration创建provider</span></span><br><span class="line">        UnmarshallerProvider provider = <span class="keyword">new</span> DefaultUnmarshallerProvider(marshallerFactory, configuration);</span><br><span class="line">        <span class="comment">//构建Netty的MarshallingDecoder对象，俩个参数分别为provider和单个消息序列化后的最大长度</span></span><br><span class="line">        MarshallingDecoder decoder = <span class="keyword">new</span> MarshallingDecoder(provider, <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">1</span>);</span><br><span class="line">        <span class="keyword">return</span> decoder;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建Jboss Marshalling编码器MarshallingEncoder</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> MarshallingEncoder</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> MarshallingEncoder <span class="title">buildMarshallingEncoder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory(<span class="string">"serial"</span>);</span><br><span class="line">        <span class="keyword">final</span> MarshallingConfiguration configuration = <span class="keyword">new</span> MarshallingConfiguration();</span><br><span class="line">        configuration.setVersion(<span class="number">5</span>);</span><br><span class="line">        MarshallerProvider provider = <span class="keyword">new</span> DefaultMarshallerProvider(marshallerFactory, configuration);</span><br><span class="line">        <span class="comment">//构建Netty的MarshallingEncoder对象，MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组</span></span><br><span class="line">        MarshallingEncoder encoder = <span class="keyword">new</span> MarshallingEncoder(provider);</span><br><span class="line">        <span class="keyword">return</span> encoder;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>HeatbeatMessage</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HeatbeatMessage</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">2827219147304706826L</span>;</span><br><span class="line">    <span class="keyword">private</span> String ip;</span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; cpuMsgMap;</span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; memMsgMap;</span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; fileSysMsgMap;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"HeatbeatMessage [\nip="</span> + ip </span><br><span class="line">                + <span class="string">", \ncpuMsgMap="</span> + cpuMsgMap </span><br><span class="line">                + <span class="string">", \nmemMsgMap="</span> + memMsgMap</span><br><span class="line">                + <span class="string">", \nfileSysMsgMap="</span> + fileSysMsgMap + <span class="string">"]"</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getIp</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> ip;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setIp</span><span class="params">(String ip)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.ip = ip;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">getCpuMsgMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> cpuMsgMap;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCpuMsgMap</span><span class="params">(Map&lt;String, Object&gt; cpuMsgMap)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.cpuMsgMap = cpuMsgMap;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">getMemMsgMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> memMsgMap;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMemMsgMap</span><span class="params">(Map&lt;String, Object&gt; memMsgMap)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.memMsgMap = memMsgMap;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title">getFileSysMsgMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> fileSysMsgMap;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setFileSysMsgMap</span><span class="params">(Map&lt;String, Object&gt; fileSysMsgMap)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.fileSysMsgMap = fileSysMsgMap;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>RequestMessage</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RequestMessage</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">7084843947860990140L</span>;</span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> String message;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">byte</span>[] attachment;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"RequestMessage [id="</span> + id + <span class="string">", message="</span> + message + <span class="string">"]"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">RequestMessage</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">RequestMessage</span><span class="params">(Long id, String message, <span class="keyword">byte</span>[] attachment)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>();</span><br><span class="line">        <span class="keyword">this</span>.id = id;</span><br><span class="line">        <span class="keyword">this</span>.message = message;</span><br><span class="line">        <span class="keyword">this</span>.attachment = attachment;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Long <span class="title">getId</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setId</span><span class="params">(Long id)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.id = id;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getMessage</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> message;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMessage</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.message = message;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">byte</span>[] getAttachment() &#123;</span><br><span class="line">        <span class="keyword">return</span> attachment;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAttachment</span><span class="params">(<span class="keyword">byte</span>[] attachment)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.attachment = attachment;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>ResponseMessage</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ResponseMessage</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">8134313953478922076L</span>;</span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> String message;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"ResponseMessage [id="</span> + id + <span class="string">", message="</span> + message + <span class="string">"]"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ResponseMessage</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ResponseMessage</span><span class="params">(Long id, String message)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>();</span><br><span class="line">        <span class="keyword">this</span>.id = id;</span><br><span class="line">        <span class="keyword">this</span>.message = message;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Long <span class="title">getId</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setId</span><span class="params">(Long id)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.id = id;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getMessage</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> message;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMessage</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.message = message;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>server端开发：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1. 双线程组</span></span><br><span class="line"><span class="comment"> * 2. Bootstrap配置启动信息</span></span><br><span class="line"><span class="comment"> * 3. 注册业务处理Handler</span></span><br><span class="line"><span class="comment"> * 4. 绑定服务监听端口并启动服务</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4HelloWorld</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 监听线程组，监听客户端请求</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup acceptorGroup = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 处理客户端相关操作线程组，负责处理与客户端的数据通讯</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup clientGroup = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 服务端启动相关配置信息</span></span><br><span class="line">    <span class="keyword">private</span> ServerBootstrap bootstrap = <span class="keyword">null</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Server4HelloWorld</span><span class="params">()</span></span>&#123;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">// 初始化线程组,构建线程组的时候，如果不传递参数，则默认构建的线程组线程数是CPU核心数量。</span></span><br><span class="line">        acceptorGroup = <span class="keyword">new</span> NioEventLoopGroup();    <span class="comment">//监听线程组</span></span><br><span class="line">        clientGroup = <span class="keyword">new</span> NioEventLoopGroup();        <span class="comment">//处理客户端线程组</span></span><br><span class="line">        <span class="comment">// 初始化服务的配置</span></span><br><span class="line">        bootstrap = <span class="keyword">new</span> ServerBootstrap();</span><br><span class="line">        <span class="comment">// 绑定线程组</span></span><br><span class="line">        bootstrap.group(acceptorGroup, clientGroup);</span><br><span class="line">        <span class="comment">// 设定通讯模式为NIO， 同步非阻塞</span></span><br><span class="line">        bootstrap.channel(NioServerSocketChannel.class);</span><br><span class="line">        <span class="comment">// 设定缓冲区大小， 缓存区的单位是字节。</span></span><br><span class="line">        bootstrap.option(ChannelOption.SO_BACKLOG, <span class="number">1024</span>);</span><br><span class="line">        <span class="comment">// SO_SNDBUF发送缓冲区，SO_RCVBUF接收缓冲区，SO_KEEPALIVE开启心跳监测（保证连接有效）</span></span><br><span class="line">        bootstrap.option(ChannelOption.SO_SNDBUF, <span class="number">16</span>*<span class="number">1024</span>)</span><br><span class="line">            .option(ChannelOption.SO_RCVBUF, <span class="number">16</span>*<span class="number">1024</span>)</span><br><span class="line">            .option(ChannelOption.SO_KEEPALIVE, <span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 监听处理逻辑。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> port 监听端口。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> acceptorHandlers 处理器， 如何处理客户端请求。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> InterruptedException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port, <span class="keyword">final</span> ChannelHandler... acceptorHandlers)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * childHandler是服务的Bootstrap独有的方法。是用于提供处理对象的。</span></span><br><span class="line"><span class="comment">         * 可以一次性增加若干个处理逻辑。是类似责任链模式的处理方式。</span></span><br><span class="line"><span class="comment">         * 增加A，B两个处理逻辑，在处理客户端请求数据的时候，根据A-》B顺序依次处理。</span></span><br><span class="line"><span class="comment">         * </span></span><br><span class="line"><span class="comment">         * ChannelInitializer - 用于提供处理器的一个模型对象。</span></span><br><span class="line"><span class="comment">         *  其中定义了一个方法，initChannel方法。</span></span><br><span class="line"><span class="comment">         *   方法是用于初始化处理逻辑责任链条的。</span></span><br><span class="line"><span class="comment">         *   可以保证服务端的Bootstrap只初始化一次处理器，尽量提供处理逻辑的重用。</span></span><br><span class="line"><span class="comment">         *   避免反复的创建处理器对象。节约资源开销。</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                ch.pipeline().addLast(acceptorHandlers);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">// bind方法 - 绑定监听端口的。ServerBootstrap可以绑定多个监听端口。 多次调用bind方法即可</span></span><br><span class="line">        <span class="comment">// sync - 开始监听逻辑。 返回一个ChannelFuture。 返回结果代表的是监听成功后的一个对应的未来结果</span></span><br><span class="line">        <span class="comment">// 可以使用ChannelFuture实现后续的服务器和客户端的交互。</span></span><br><span class="line">        ChannelFuture future = bootstrap.bind(port).sync();</span><br><span class="line">        <span class="keyword">return</span> future;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * shutdownGracefully - 方法是一个安全关闭的方法。可以保证不放弃任何一个已接收的客户端请求。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.acceptorGroup.shutdownGracefully();</span><br><span class="line">        <span class="keyword">this</span>.clientGroup.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">        Server4HelloWorld server = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            server = <span class="keyword">new</span> Server4HelloWorld();</span><br><span class="line">            future = server.doAccept(<span class="number">9999</span>,<span class="keyword">new</span> Server4HelloWorldHandler());</span><br><span class="line">            System.out.println(<span class="string">"server started."</span>);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 关闭连接的。</span></span><br><span class="line">            future.channel().closeFuture().sync();</span><br><span class="line">        &#125;<span class="keyword">catch</span>(InterruptedException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    future.channel().closeFuture().sync();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//回收线程组资源</span></span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != server)&#123;</span><br><span class="line">                server.release();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Sharable</span>注解 - </span></span><br><span class="line"><span class="comment"> *  代表当前Handler是一个可以分享的处理器。也就意味着，服务器注册此Handler后，可以分享给多个客户端同时使用。</span></span><br><span class="line"><span class="comment"> *  如果不使用注解描述类型，则每次客户端请求时，必须为客户端重新创建一个新的Handler对象。</span></span><br><span class="line"><span class="comment"> *  如果handler是一个Sharable的，一定避免定义可写的实例变量。修改会发生混乱</span></span><br><span class="line"><span class="comment"> *  bootstrap.childHandler(new ChannelInitializer&lt;SocketChannel&gt;() &#123;</span></span><br><span class="line"><span class="comment">            <span class="doctag">@Override</span></span></span><br><span class="line"><span class="comment">            protected void initChannel(SocketChannel ch) throws Exception &#123;</span></span><br><span class="line"><span class="comment">                ch.pipeline().addLast(new XxxHandler());</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">        &#125;);</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">package</span> com.sxt.netty.first;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.ByteBuf;</span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.Unpooled;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelFutureListener;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandler.Sharable;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.SocketChannel;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandlerAdapter;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandlerContext;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelInitializer;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Sharable</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4HelloWorldHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 业务处理逻辑</span></span><br><span class="line"><span class="comment">     * 用于处理读取数据请求的逻辑。</span></span><br><span class="line"><span class="comment">     * ctx - 上下文对象。其中包含于客户端建立连接的所有资源。 如： 对应的Channel</span></span><br><span class="line"><span class="comment">     * msg - 读取到的数据。 默认类型是ByteBuf，是Netty自定义的。是对ByteBuffer的封装。 不需要考虑复位问题。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">// 获取读取的数据， 是一个缓冲。</span></span><br><span class="line">        ByteBuf readBuffer = (ByteBuf) msg;</span><br><span class="line">        <span class="comment">// 创建一个字节数组，用于保存缓存中的数据。</span></span><br><span class="line">        <span class="keyword">byte</span>[] tempDatas = <span class="keyword">new</span> <span class="keyword">byte</span>[readBuffer.readableBytes()];</span><br><span class="line">        <span class="comment">// 将缓存中的数据读取到字节数组中。</span></span><br><span class="line">        readBuffer.readBytes(tempDatas);</span><br><span class="line">        String message = <span class="keyword">new</span> String(tempDatas, <span class="string">"UTF-8"</span>);</span><br><span class="line">        System.out.println(<span class="string">"from client : "</span> + message);</span><br><span class="line">        <span class="keyword">if</span>(<span class="string">"exit"</span>.equals(message))&#123;</span><br><span class="line">            ctx.close();</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        String line = <span class="string">"server message to client!"</span>;</span><br><span class="line">        <span class="comment">// 写操作自动释放缓存，避免内存溢出问题。</span></span><br><span class="line">        ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes(<span class="string">"UTF-8"</span>)));</span><br><span class="line">        <span class="comment">// 注意，如果调用的是write方法。不会刷新缓存，缓存中的数据不会发送到客户端，必须再次调用flush方法才行。</span></span><br><span class="line">        <span class="comment">// ctx.write(Unpooled.copiedBuffer(line.getBytes("UTF-8")));</span></span><br><span class="line">        <span class="comment">// ctx.flush()</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 异常处理逻辑， 当客户端异常退出的时候，也会运行。</span></span><br><span class="line"><span class="comment">     * ChannelHandlerContext关闭，也代表当前与客户端连接的资源关闭。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"server exceptionCaught method run..."</span>);</span><br><span class="line">        <span class="comment">// cause.printStackTrace();</span></span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>client</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 因为客户端是请求的发起者，不需要监听。</span></span><br><span class="line"><span class="comment"> * 只需要定义唯一的一个线程组即可。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4HelloWorld</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理请求和处理服务端响应的线程组</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup group = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 客户端启动相关配置信息</span></span><br><span class="line">    <span class="keyword">private</span> Bootstrap bootstrap = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Client4HelloWorld</span><span class="params">()</span></span>&#123;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span>&#123;</span><br><span class="line">        group = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        bootstrap = <span class="keyword">new</span> Bootstrap();</span><br><span class="line">        <span class="comment">// 绑定线程组</span></span><br><span class="line">        bootstrap.group(group);</span><br><span class="line">        <span class="comment">// 设定通讯模式为NIO</span></span><br><span class="line">        bootstrap.channel(NioSocketChannel.class);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doRequest</span><span class="params">(String host, <span class="keyword">int</span> port, <span class="keyword">final</span> ChannelHandler... handlers)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * 客户端的Bootstrap没有childHandler方法。只有handler方法。</span></span><br><span class="line"><span class="comment">         * 方法含义等同ServerBootstrap中的childHandler</span></span><br><span class="line"><span class="comment">         * 在客户端必须绑定处理器，也就是必须调用handler方法。</span></span><br><span class="line"><span class="comment">         * 服务器必须绑定处理器，必须调用childHandler方法。</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">this</span>.bootstrap.handler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                ch.pipeline().addLast(handlers);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">// 建立连接。</span></span><br><span class="line">        ChannelFuture future = <span class="keyword">this</span>.bootstrap.connect(host, port).sync();</span><br><span class="line">        <span class="keyword">return</span> future;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.group.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Client4HelloWorld client = <span class="keyword">null</span>;</span><br><span class="line">        ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            client = <span class="keyword">new</span> Client4HelloWorld();</span><br><span class="line">            future = client.doRequest(<span class="string">"localhost"</span>, <span class="number">9999</span>, <span class="keyword">new</span> Client4HelloWorldHandler());</span><br><span class="line"></span><br><span class="line">            Scanner s = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                s = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">                System.out.print(<span class="string">"enter message send to server (enter 'exit' for close client) &gt; "</span>);</span><br><span class="line">                String line = s.nextLine();</span><br><span class="line">                <span class="keyword">if</span>(<span class="string">"exit"</span>.equals(line))&#123;</span><br><span class="line">                    <span class="comment">// addListener - 增加监听，当某条件满足的时候，触发监听器。</span></span><br><span class="line">                    <span class="comment">// ChannelFutureListener.CLOSE - 关闭监听器，代表ChannelFuture执行返回后，关闭连接。</span></span><br><span class="line">                    future.channel().writeAndFlush(Unpooled.copiedBuffer(line.getBytes(<span class="string">"UTF-8"</span>)))</span><br><span class="line">                        .addListener(ChannelFutureListener.CLOSE);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                future.channel().writeAndFlush(Unpooled.copiedBuffer(line.getBytes(<span class="string">"UTF-8"</span>)));</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    future.channel().closeFuture().sync();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != client)&#123;</span><br><span class="line">                client.release();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>clientHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4HelloWorldHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            ByteBuf readBuffer = (ByteBuf) msg;</span><br><span class="line">            <span class="keyword">byte</span>[] tempDatas = <span class="keyword">new</span> <span class="keyword">byte</span>[readBuffer.readableBytes()];</span><br><span class="line">            readBuffer.readBytes(tempDatas);</span><br><span class="line">            System.out.println(<span class="string">"from server : "</span> + <span class="keyword">new</span> String(tempDatas, <span class="string">"UTF-8"</span>));</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="comment">// 用于释放缓存。避免内存溢出</span></span><br><span class="line">            ReferenceCountUtil.release(msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"client exceptionCaught method run..."</span>);</span><br><span class="line">        <span class="comment">// cause.printStackTrace();</span></span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*@Override // 断开连接时执行</span></span><br><span class="line"><span class="comment">    public void channelInactive(ChannelHandlerContext ctx) throws Exception &#123;</span></span><br><span class="line"><span class="comment">        System.out.println("channelInactive method run...");</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    @Override // 连接通道建立成功时执行</span></span><br><span class="line"><span class="comment">    public void channelActive(ChannelHandlerContext ctx) throws Exception &#123;</span></span><br><span class="line"><span class="comment">        System.out.println("channelActive method run...");</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    @Override // 每次读取完成时执行</span></span><br><span class="line"><span class="comment">    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception &#123;</span></span><br><span class="line"><span class="comment">        System.out.println("channelReadComplete method run...");</span></span><br><span class="line"><span class="comment">    &#125;*/</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="合体圆满（基础代码演示）"><a href="#合体圆满（基础代码演示）" class="headerlink" title="合体圆满（基础代码演示）"></a>合体圆满（基础代码演示）</h3><p><strong>拆包粘包问题解决</strong> ：</p>
<p>​        <em>netty</em> 使用 <em>tcp/ip</em> 协议传输数据。而 <em>tcp/ip</em> 协议是类似水流一样的数据传输方式。多次 访问的时候有可能出现数据粘包的问题。（Netty是NIO的模型，是同步非阻塞的，一定执行read/write时候就继续向下执行了，让底层的代码给我们处理执行数据的准备，怎么去读写操作，如果我们客户端发起多个数据，read方法到底是读几条数据？不知道客户端发送过来到底是几套数据，每一条间到底有什么间隔）解决这种问题的方式如下：</p>
<ul>
<li><strong>定长数据流</strong> ：客户端和服务器，提前协调好，每个消息长度固定。（如：长度 <em>10</em>）。如果客户端或服 务器写出的数据不足 <em>10</em>，则使用空白字符补足（如：使用空格）。 </li>
</ul>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1. 双线程组</span></span><br><span class="line"><span class="comment"> * 2. Bootstrap配置启动信息</span></span><br><span class="line"><span class="comment"> * 3. 注册业务处理Handler</span></span><br><span class="line"><span class="comment"> * 4. 绑定服务监听端口并启动服务</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4FixedLength</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 监听线程组，监听客户端请求</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup acceptorGroup = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 处理客户端相关操作线程组，负责处理与客户端的数据通讯</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup clientGroup = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 服务启动相关配置信息</span></span><br><span class="line">    <span class="keyword">private</span> ServerBootstrap bootstrap = <span class="keyword">null</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Server4FixedLength</span><span class="params">()</span></span>&#123;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span>&#123;</span><br><span class="line">        acceptorGroup = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        clientGroup = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        bootstrap = <span class="keyword">new</span> ServerBootstrap();</span><br><span class="line">        <span class="comment">// 绑定线程组</span></span><br><span class="line">        bootstrap.group(acceptorGroup, clientGroup);</span><br><span class="line">        <span class="comment">// 设定通讯模式为NIO</span></span><br><span class="line">        bootstrap.channel(NioServerSocketChannel.class);</span><br><span class="line">        <span class="comment">// 设定缓冲区大小</span></span><br><span class="line">        bootstrap.option(ChannelOption.SO_BACKLOG, <span class="number">1024</span>);</span><br><span class="line">        <span class="comment">// SO_SNDBUF发送缓冲区，SO_RCVBUF接收缓冲区，SO_KEEPALIVE开启心跳监测（保证连接有效）</span></span><br><span class="line">        bootstrap.option(ChannelOption.SO_SNDBUF, <span class="number">16</span>*<span class="number">1024</span>)</span><br><span class="line">            .option(ChannelOption.SO_RCVBUF, <span class="number">16</span>*<span class="number">1024</span>)</span><br><span class="line">            .option(ChannelOption.SO_KEEPALIVE, <span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">        bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                ChannelHandler[] acceptorHandlers = <span class="keyword">new</span> ChannelHandler[<span class="number">3</span>];</span><br><span class="line">                <span class="comment">// 定长Handler。通过构造参数设置消息长度（单位是字节）。发送的消息长度不足可以使用空格补全。</span></span><br><span class="line">                acceptorHandlers[<span class="number">0</span>] = <span class="keyword">new</span> FixedLengthFrameDecoder(<span class="number">3</span>);</span><br><span class="line">                <span class="comment">// 字符串解码器Handler，会自动处理channelRead方法的msg参数，将ByteBuf类型的数据转换为字符串对象</span></span><br><span class="line">                acceptorHandlers[<span class="number">1</span>] = <span class="keyword">new</span> StringDecoder(Charset.forName(<span class="string">"UTF-8"</span>));</span><br><span class="line">                acceptorHandlers[<span class="number">2</span>] = <span class="keyword">new</span> Server4FixedLengthHandler();</span><br><span class="line">                ch.pipeline().addLast(acceptorHandlers);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        ChannelFuture future = bootstrap.bind(port).sync();</span><br><span class="line">        <span class="keyword">return</span> future;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.acceptorGroup.shutdownGracefully();</span><br><span class="line">        <span class="keyword">this</span>.clientGroup.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">        Server4FixedLength server = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            server = <span class="keyword">new</span> Server4FixedLength();</span><br><span class="line"></span><br><span class="line">            future = server.doAccept(<span class="number">9999</span>);</span><br><span class="line">            System.out.println(<span class="string">"server started."</span>);</span><br><span class="line">            future.channel().closeFuture().sync();</span><br><span class="line">        &#125;<span class="keyword">catch</span>(InterruptedException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    future.channel().closeFuture().sync();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != server)&#123;</span><br><span class="line">                server.release();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4FixedLengthHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 业务处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        String message = msg.toString();</span><br><span class="line">        System.out.println(<span class="string">"from client : "</span> + message.trim());</span><br><span class="line">        String line = <span class="string">"ok "</span>;</span><br><span class="line">        ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes(<span class="string">"UTF-8"</span>)));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 异常处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"server exceptionCaught method run..."</span>);</span><br><span class="line">        <span class="comment">// cause.printStackTrace();</span></span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>client</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1. 单线程组</span></span><br><span class="line"><span class="comment"> * 2. Bootstrap配置启动信息</span></span><br><span class="line"><span class="comment"> * 3. 注册业务处理Handler</span></span><br><span class="line"><span class="comment"> * 4. connect连接服务，并发起请求</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4FixedLength</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理请求和处理服务端响应的线程组</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup group = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 服务启动相关配置信息</span></span><br><span class="line">    <span class="keyword">private</span> Bootstrap bootstrap = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Client4FixedLength</span><span class="params">()</span></span>&#123;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span>&#123;</span><br><span class="line">        group = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        bootstrap = <span class="keyword">new</span> Bootstrap();</span><br><span class="line">        <span class="comment">// 绑定线程组</span></span><br><span class="line">        bootstrap.group(group);</span><br><span class="line">        <span class="comment">// 设定通讯模式为NIO</span></span><br><span class="line">        bootstrap.channel(NioSocketChannel.class);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doRequest</span><span class="params">(String host, <span class="keyword">int</span> port)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.bootstrap.handler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                ChannelHandler[] handlers = <span class="keyword">new</span> ChannelHandler[<span class="number">3</span>];</span><br><span class="line">                handlers[<span class="number">0</span>] = <span class="keyword">new</span> FixedLengthFrameDecoder(<span class="number">3</span>);</span><br><span class="line">                <span class="comment">// 字符串解码器Handler，会自动处理channelRead方法的msg参数，将ByteBuf类型的数据转换为字符串对象</span></span><br><span class="line">                handlers[<span class="number">1</span>] = <span class="keyword">new</span> StringDecoder(Charset.forName(<span class="string">"UTF-8"</span>));</span><br><span class="line">                handlers[<span class="number">2</span>] = <span class="keyword">new</span> Client4FixedLengthHandler();</span><br><span class="line"></span><br><span class="line">                ch.pipeline().addLast(handlers);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        ChannelFuture future = <span class="keyword">this</span>.bootstrap.connect(host, port).sync();</span><br><span class="line">        <span class="keyword">return</span> future;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.group.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Client4FixedLength client = <span class="keyword">null</span>;</span><br><span class="line">        ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            client = <span class="keyword">new</span> Client4FixedLength();</span><br><span class="line"></span><br><span class="line">            future = client.doRequest(<span class="string">"localhost"</span>, <span class="number">9999</span>);</span><br><span class="line"></span><br><span class="line">            Scanner s = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">                s = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">                System.out.print(<span class="string">"enter message send to server &gt; "</span>);</span><br><span class="line">                String line = s.nextLine();</span><br><span class="line">                <span class="keyword">byte</span>[] bs = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">5</span>];</span><br><span class="line">                <span class="keyword">byte</span>[] temp = line.getBytes(<span class="string">"UTF-8"</span>);</span><br><span class="line">                <span class="keyword">if</span>(temp.length &lt;= <span class="number">5</span>)&#123;</span><br><span class="line">                    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; temp.length; i++)&#123;</span><br><span class="line">                        bs[i] = temp[i];</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                future.channel().writeAndFlush(Unpooled.copiedBuffer(bs));</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    future.channel().closeFuture().sync();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != client)&#123;</span><br><span class="line">                client.release();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>clientHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4FixedLengthHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            String message = msg.toString();</span><br><span class="line">            System.out.println(<span class="string">"from server : "</span> + message);</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="comment">// 用于释放缓存。避免内存溢出</span></span><br><span class="line">            ReferenceCountUtil.release(msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"client exceptionCaught method run..."</span>);</span><br><span class="line">        <span class="comment">// cause.printStackTrace();</span></span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>注意：此时客户端只要不能满足的数据是3的长度，要可以进行多次发送。服务端才能收到数据，并且是连起来的。当客户端发的是大3的长度是，如发送abc123def4，服务器会把它当成三条数据，4不会出来，客户端在发送2个长度数据，服务端才可以接收到。</p>
<p>​        中文问题，unicode中，一个汉字可能长度是2也可能是3。如果在上面代码中的客户端发送”中国”二个字就有意思了。服务端会接收到2次，一个字一次。</p>
<ul>
<li><p><strong>特殊结束符</strong> ：客户端和服务器，协商定义一个特殊的分隔符号，分隔符号长度自定义。如：‘<em>#</em>’、‘<em>$_$</em>’、 </p>
<p>‘<em>AA@</em>’。在通讯的时候，只要没有发送分隔符号，则代表一条数据没有结束。</p>
</li>
</ul>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">    bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            <span class="comment">// 数据分隔符, 定义的数据分隔符一定是一个ByteBuf类型的数据对象。</span></span><br><span class="line">            ByteBuf delimiter = Unpooled.copiedBuffer(<span class="string">"$E$"</span>.getBytes());</span><br><span class="line">            ChannelHandler[] acceptorHandlers = <span class="keyword">new</span> ChannelHandler[<span class="number">3</span>];</span><br><span class="line">            <span class="comment">// 处理固定结束标记符号的Handler。这个Handler没有@Sharable注解修饰，</span></span><br><span class="line">            <span class="comment">// 必须每次初始化通道时创建一个新对象</span></span><br><span class="line">            <span class="comment">// 使用特殊符号分隔处理数据粘包问题，也要定义每个数据包最大长度。netty建议数据有最大长度。</span></span><br><span class="line">            acceptorHandlers[<span class="number">0</span>] = <span class="keyword">new</span> DelimiterBasedFrameDecoder(<span class="number">1024</span>, delimiter);</span><br><span class="line">            <span class="comment">// 字符串解码器Handler，会自动处理channelRead方法的msg参数，将ByteBuf类型的数据转换为字符串对象</span></span><br><span class="line">            acceptorHandlers[<span class="number">1</span>] = <span class="keyword">new</span> StringDecoder(Charset.forName(<span class="string">"UTF-8"</span>));</span><br><span class="line">            acceptorHandlers[<span class="number">2</span>] = <span class="keyword">new</span> Server4DelimiterHandler();</span><br><span class="line">            ch.pipeline().addLast(acceptorHandlers);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    ChannelFuture future = bootstrap.bind(port).sync();</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 业务处理逻辑</span></span><br><span class="line"><span class="meta">@Overridepublic</span> <span class="function"><span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;   </span><br><span class="line">    String message = msg.toString();   </span><br><span class="line">    System.out.println(<span class="string">"from client : "</span> + message);   </span><br><span class="line">    <span class="comment">//会放回三条字符串   </span></span><br><span class="line">    String line = <span class="string">"server message $E$ test delimiter handler!! $E$ second message $E$"</span>;         ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes(<span class="string">"UTF-8"</span>)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>client和server改动基本一样。此时如果客户端不输入分隔符，可以进行不断输入。</p>
<ul>
<li><p><strong>协议</strong> ：相对最成熟的数据传递方式。有服务器的开发者提供一个固定格式的协议标准。客户端 </p>
<p>和服务器发送数据和接受数据的时候，都依据协议制定和解析消息。</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">协议格式：HEADcontent-length:xxxxHEADBODYxxxxxxBODY</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port, <span class="keyword">final</span> ChannelHandler... acceptorHandlers)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">    bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            ch.pipeline().addLast(<span class="keyword">new</span> StringDecoder(Charset.forName(<span class="string">"UTF-8"</span>)));</span><br><span class="line">            ch.pipeline().addLast(acceptorHandlers);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    ChannelFuture future = bootstrap.bind(port).sync();</span><br><span class="line">    <span class="keyword">return</span> future;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Sharable</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4ProtocolHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 业务处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        String message = msg.toString();</span><br><span class="line">        System.out.println(<span class="string">"server receive protocol content : "</span> + message);</span><br><span class="line">        message = ProtocolParser.parse(message);</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> == message)&#123;</span><br><span class="line">            System.out.println(<span class="string">"error request from client"</span>);</span><br><span class="line">            <span class="keyword">return</span> ;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"from client : "</span> + message);</span><br><span class="line">        String line = <span class="string">"server message"</span>;</span><br><span class="line">        line = ProtocolParser.transferTo(line);</span><br><span class="line">        System.out.println(<span class="string">"server send protocol content : "</span> + line);</span><br><span class="line">        ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes(<span class="string">"UTF-8"</span>)));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 异常处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"server exceptionCaught method run..."</span>);</span><br><span class="line">        cause.printStackTrace();</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ProtocolParser</span></span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">parse</span><span class="params">(String message)</span></span>&#123;</span><br><span class="line">            String[] temp = message.split(<span class="string">"HEADBODY"</span>);</span><br><span class="line">            temp[<span class="number">0</span>] = temp[<span class="number">0</span>].substring(<span class="number">4</span>);</span><br><span class="line">            temp[<span class="number">1</span>] = temp[<span class="number">1</span>].substring(<span class="number">0</span>, (temp[<span class="number">1</span>].length()-<span class="number">4</span>));</span><br><span class="line">            <span class="keyword">int</span> length = Integer.parseInt(temp[<span class="number">0</span>].substring(temp[<span class="number">0</span>].indexOf(<span class="string">":"</span>)+<span class="number">1</span>));</span><br><span class="line">            <span class="keyword">if</span>(length != temp[<span class="number">1</span>].length())&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> temp[<span class="number">1</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">transferTo</span><span class="params">(String message)</span></span>&#123;</span><br><span class="line">            message = <span class="string">"HEADcontent-length:"</span> + message.length() + <span class="string">"HEADBODY"</span> + message + <span class="string">"BODY"</span>;</span><br><span class="line">            <span class="keyword">return</span> message;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>协议限定拆分的格式。解决粘包。</p>
<ul>
<li><strong>序列化对象</strong> ：<em>JBoss Marshalling</em> 序列化 ，<em>Java</em> 是面向对象的开发语言。传递的数据如果是 <em>Java</em> 对象，应该是最方便且可靠。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port, <span class="keyword">final</span> ChannelHandler... acceptorHandlers)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">    bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingDecoder());</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingEncoder());</span><br><span class="line">            ch.pipeline().addLast(acceptorHandlers);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    ChannelFuture future = bootstrap.bind(port).sync();</span><br><span class="line">    <span class="keyword">return</span> future;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Sharable</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4SerializableHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 业务处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"from client : ClassName - "</span> + msg.getClass().getName()</span><br><span class="line">                + <span class="string">" ; message : "</span> + msg.toString());</span><br><span class="line">        <span class="keyword">if</span>(msg <span class="keyword">instanceof</span> RequestMessage)&#123;</span><br><span class="line">            RequestMessage request = (RequestMessage)msg;</span><br><span class="line">            <span class="comment">// 解压缩</span></span><br><span class="line">            <span class="comment">// byte[] attachment = GzipUtils.unzip(request.getAttachment());</span></span><br><span class="line">            <span class="comment">// System.out.println(new String(attachment));</span></span><br><span class="line">        &#125;</span><br><span class="line">        ResponseMessage response = <span class="keyword">new</span> ResponseMessage(<span class="number">0L</span>, <span class="string">"test response"</span>);</span><br><span class="line">        ctx.writeAndFlush(response);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 异常处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"server exceptionCaught method run..."</span>);</span><br><span class="line">        cause.printStackTrace();</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>client</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doRequest</span><span class="params">(String host, <span class="keyword">int</span> port, <span class="keyword">final</span> ChannelHandler... handlers)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.bootstrap.handler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingDecoder());</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingEncoder());</span><br><span class="line">            ch.pipeline().addLast(handlers);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    ChannelFuture future = <span class="keyword">this</span>.bootstrap.connect(host, port).sync();</span><br><span class="line">    <span class="keyword">return</span> future;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.group.shutdownGracefully();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    Client4Serializable client = <span class="keyword">null</span>;</span><br><span class="line">    ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span>&#123;</span><br><span class="line">        client = <span class="keyword">new</span> Client4Serializable();</span><br><span class="line">        future = client.doRequest(<span class="string">"localhost"</span>, <span class="number">9999</span>, <span class="keyword">new</span> Client4SerializableHandler());</span><br><span class="line">        String attachment = <span class="string">"test attachment"</span>;</span><br><span class="line">        <span class="keyword">byte</span>[] attBuf = attachment.getBytes();</span><br><span class="line">        <span class="comment">// attBuf = GzipUtils.zip(attBuf);</span></span><br><span class="line">        <span class="comment">// RequestMessage msg = new RequestMessage(new Random().nextLong(), </span></span><br><span class="line">        <span class="comment">//        "test", new byte[0]);</span></span><br><span class="line">        <span class="comment">// 压缩，有效减少网络中传递的数据</span></span><br><span class="line">        attBuf = GzipUtils.zip(attBuf);</span><br><span class="line">        RequestMessage msg = <span class="keyword">new</span> RequestMessage(<span class="keyword">new</span> Random().nextLong(), </span><br><span class="line">            <span class="string">"test"</span>, attBuf);</span><br><span class="line">        future.channel().writeAndFlush(msg);</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        future.addListener(ChannelFutureListener.CLOSE);</span><br><span class="line">    &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                future.channel().closeFuture().sync();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> != client)&#123;</span><br><span class="line">            client.release();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>clientHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4SerializableHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"from server : ClassName - "</span> + msg.getClass().getName()</span><br><span class="line">                + <span class="string">" ; message : "</span> + msg.toString());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"client exceptionCaught method run..."</span>);</span><br><span class="line">        cause.printStackTrace();</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><strong>定时断线重连</strong> ：客户端断线重连机制。 客户端数量多，且需要传递的数据量级较大。可以周期性的发送数据的时候，使用。要 求对数据的即时性不高的时候，才可使用。 优点： 可以使用数据缓存。不是每条数据进行一次数据交互。可以定时回收资源，对 资源利用率高。相对来说，即时性可以通过其他方式保证。如： <em>120</em> 秒自动断线。数据变 化 <em>1000</em> 次请求服务器一次。<em>300</em> 秒中自动发送不足 <em>1000</em> 次的变化数据（Timer）。</li>
</ul>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">    bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingDecoder());</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingEncoder());</span><br><span class="line">            <span class="comment">// 定义一个定时断线处理器，当多长时间内，没有任何的可读取数据，自动断开连接。</span></span><br><span class="line">            <span class="comment">// 没有@Sharable的</span></span><br><span class="line">            <span class="comment">// 构造参数，就是间隔时长。 默认的单位是秒。</span></span><br><span class="line">            <span class="comment">// 自定义间隔时长单位。 new ReadTimeoutHandler(long times, TimeUnit unit);</span></span><br><span class="line">            ch.pipeline().addLast(<span class="keyword">new</span> ReadTimeoutHandler(<span class="number">3</span>));</span><br><span class="line">            ch.pipeline().addLast(<span class="keyword">new</span> Server4TimerHandler());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    ChannelFuture future = bootstrap.bind(port).sync();</span><br><span class="line">    <span class="keyword">return</span> future;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>client</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setHandlers</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.bootstrap.handler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingDecoder());</span><br><span class="line">            ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingEncoder());</span><br><span class="line">            <span class="comment">// 写操作自定断线。 在指定时间内，没有写操作，自动断线。</span></span><br><span class="line">            ch.pipeline().addLast(<span class="keyword">new</span> WriteTimeoutHandler(<span class="number">3</span>));</span><br><span class="line">            ch.pipeline().addLast(<span class="keyword">new</span> Client4TimerHandler());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">getChannelFuture</span><span class="params">(String host, <span class="keyword">int</span> port)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line">    <span class="comment">// future是null，我们就要建立连接</span></span><br><span class="line">    <span class="keyword">if</span>(future == <span class="keyword">null</span>)&#123;</span><br><span class="line">        future = <span class="keyword">this</span>.bootstrap.connect(host, port).sync();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 如果非空，看些连接未来状态中的通道是否有效。</span></span><br><span class="line">    <span class="comment">// 如果future非空，但是有个channel，证明已经和服务器断开了，但是future没有被回收</span></span><br><span class="line">    <span class="comment">// 重连操作</span></span><br><span class="line">    <span class="keyword">if</span>(!future.channel().isActive())&#123;</span><br><span class="line">        future = <span class="keyword">this</span>.bootstrap.connect(host, port).sync();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> future;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.group.shutdownGracefully();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    Client4Timer client = <span class="keyword">null</span>;</span><br><span class="line">    ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span>&#123;</span><br><span class="line">        client = <span class="keyword">new</span> Client4Timer();</span><br><span class="line">        client.setHandlers();</span><br><span class="line"></span><br><span class="line">        future = client.getChannelFuture(<span class="string">"localhost"</span>, <span class="number">9999</span>);</span><br><span class="line">        <span class="comment">// 循环3从。睡眠2秒，没有超出时长</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++)&#123;</span><br><span class="line">            RequestMessage msg = <span class="keyword">new</span> RequestMessage(<span class="keyword">new</span> Random().nextLong(), </span><br><span class="line">                    <span class="string">"test"</span>+i, <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">0</span>]);</span><br><span class="line">            future.channel().writeAndFlush(msg);</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 有超出时长</span></span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">        future = client.getChannelFuture(<span class="string">"localhost"</span>, <span class="number">9999</span>);</span><br><span class="line">        RequestMessage msg = <span class="keyword">new</span> RequestMessage(<span class="keyword">new</span> Random().nextLong(), </span><br><span class="line">                <span class="string">"test"</span>, <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">0</span>]);</span><br><span class="line">        future.channel().writeAndFlush(msg);</span><br><span class="line">    &#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                future.channel().closeFuture().sync();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">null</span> != client)&#123;</span><br><span class="line">            client.release();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>clientHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4TimerHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"from server : ClassName - "</span> + msg.getClass().getName()</span><br><span class="line">                + <span class="string">" ; message : "</span> + msg.toString());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"client exceptionCaught method run..."</span>);</span><br><span class="line">        cause.printStackTrace();</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当连接建立成功后，出发的代码逻辑。</span></span><br><span class="line"><span class="comment">     * 在一次连接中只运行唯一一次。</span></span><br><span class="line"><span class="comment">     * 通常用于实现连接确认和资源初始化的。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelActive</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"client channel active"</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>server端运行图。有断线有异常，</p>
<p><img src="\media\1582293141(1" alt="">.jpg)</p>
<p><img src="\media\1582293463(1" alt="">.jpg)</p>
<ul>
<li><strong>心跳监测</strong> ：使用定时发送消息的方式，实现硬件检测，达到心态检测的目的。 心跳监测是用于检测电脑硬件和软件信息的一种技术。如：<em>CPU</em> 使用率，磁盘使用率， 内存使用率，进程情况，线程情况等。 </li>
<li><strong>sigar</strong> ：需要下载一个 <em>zip</em> 压缩包。内部包含若干 <em>sigar</em> 需要的操作系统文件。<em>sigar</em> 插件是通过 <em>JVM</em> 访问操作系统，读取计算机硬件的一个插件库。读取计算机硬件过程中，必须由操作系统提供硬件信息。硬件信息是通过操作系统提供的。<em>zip</em> 压缩包中是 <em>sigar</em> 编写的操作系统文 件，如：<em>windows</em> 中的动态链接库文件。 解压需要的操作系统文件，将操作系统文件赋值到<em>${Java_home}/bin</em> 目录中。</li>
</ul>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4Heatbeat</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 监听线程组，监听客户端请求</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup acceptorGroup = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 处理客户端相关操作线程组，负责处理与客户端的数据通讯</span></span><br><span class="line">    <span class="keyword">private</span> EventLoopGroup clientGroup = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 服务启动相关配置信息</span></span><br><span class="line">    <span class="keyword">private</span> ServerBootstrap bootstrap = <span class="keyword">null</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Server4Heatbeat</span><span class="params">()</span></span>&#123;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span>&#123;</span><br><span class="line">        acceptorGroup = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        clientGroup = <span class="keyword">new</span> NioEventLoopGroup();</span><br><span class="line">        bootstrap = <span class="keyword">new</span> ServerBootstrap();</span><br><span class="line">        <span class="comment">// 绑定线程组</span></span><br><span class="line">        bootstrap.group(acceptorGroup, clientGroup);</span><br><span class="line">        <span class="comment">// 设定通讯模式为NIO</span></span><br><span class="line">        bootstrap.channel(NioServerSocketChannel.class);</span><br><span class="line">        <span class="comment">// 设定缓冲区大小</span></span><br><span class="line">        bootstrap.option(ChannelOption.SO_BACKLOG, <span class="number">1024</span>);</span><br><span class="line">        <span class="comment">// SO_SNDBUF发送缓冲区，SO_RCVBUF接收缓冲区，SO_KEEPALIVE开启心跳监测（保证连接有效）</span></span><br><span class="line">        bootstrap.option(ChannelOption.SO_SNDBUF, <span class="number">16</span>*<span class="number">1024</span>)</span><br><span class="line">            .option(ChannelOption.SO_RCVBUF, <span class="number">16</span>*<span class="number">1024</span>)</span><br><span class="line">            .option(ChannelOption.SO_KEEPALIVE, <span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> ChannelFuture <span class="title">doAccept</span><span class="params">(<span class="keyword">int</span> port)</span> <span class="keyword">throws</span> InterruptedException</span>&#123;</span><br><span class="line"></span><br><span class="line">        bootstrap.childHandler(<span class="keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">                ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingDecoder());</span><br><span class="line">                ch.pipeline().addLast(SerializableFactory4Marshalling.buildMarshallingEncoder());</span><br><span class="line">                ch.pipeline().addLast(<span class="keyword">new</span> Server4HeatbeatHandler());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        ChannelFuture future = bootstrap.bind(port).sync();</span><br><span class="line">        <span class="keyword">return</span> future;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.acceptorGroup.shutdownGracefully();</span><br><span class="line">        <span class="keyword">this</span>.clientGroup.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        ChannelFuture future = <span class="keyword">null</span>;</span><br><span class="line">        Server4Heatbeat server = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            server = <span class="keyword">new</span> Server4Heatbeat();</span><br><span class="line">            future = server.doAccept(<span class="number">9999</span>);</span><br><span class="line">            System.out.println(<span class="string">"server started."</span>);</span><br><span class="line"></span><br><span class="line">            future.channel().closeFuture().sync();</span><br><span class="line">        &#125;<span class="keyword">catch</span>(InterruptedException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != future)&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    future.channel().closeFuture().sync();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">null</span> != server)&#123;</span><br><span class="line">                server.release();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Sharable</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server4HeatbeatHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> List&lt;String&gt; credentials = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String HEATBEAT_SUCCESS = <span class="string">"SERVER_RETURN_HEATBEAT_SUCCESS"</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Server4HeatbeatHandler</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">// 初始化客户端列表信息。一般通过配置文件读取或数据库读取。</span></span><br><span class="line">        credentials.add(<span class="string">"192.168.199.222_WIN-QIUB2JF5TDP"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 业务处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(msg <span class="keyword">instanceof</span> String)&#123;</span><br><span class="line">            <span class="keyword">this</span>.checkCredential(ctx, msg.toString());</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (msg <span class="keyword">instanceof</span> HeatbeatMessage)&#123;</span><br><span class="line">            <span class="keyword">this</span>.readHeatbeatMessage(ctx, msg);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 服务器发送的信息是错误的，或者对外暴露的ip和端口号被与系统无关的人访问到了，自动断开连接</span></span><br><span class="line">            ctx.writeAndFlush(<span class="string">"wrong message"</span>).addListener(ChannelFutureListener.CLOSE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readHeatbeatMessage</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span></span>&#123;</span><br><span class="line">        HeatbeatMessage message = (HeatbeatMessage) msg;</span><br><span class="line">        System.out.println(message);</span><br><span class="line">        System.out.println(<span class="string">"======================================="</span>);</span><br><span class="line">        ctx.writeAndFlush(<span class="string">"receive heatbeat message"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 身份检查。检查客户端身份是否有效。</span></span><br><span class="line"><span class="comment">     * 客户端身份信息应该是通过数据库或数据文件定制的。</span></span><br><span class="line"><span class="comment">     * 身份通过 - 返回确认消息。</span></span><br><span class="line"><span class="comment">     * 身份无效 - 断开连接</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ctx</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> credential</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">checkCredential</span><span class="params">(ChannelHandlerContext ctx, String credential)</span></span>&#123;</span><br><span class="line">        System.out.println(credential);</span><br><span class="line">        System.out.println(credentials);</span><br><span class="line">        <span class="keyword">if</span>(credentials.contains(credential))&#123;</span><br><span class="line">            ctx.writeAndFlush(HEATBEAT_SUCCESS);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            ctx.writeAndFlush(<span class="string">"no credential contains"</span>).addListener(ChannelFutureListener.CLOSE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 异常处理逻辑</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"server exceptionCaught method run..."</span>);</span><br><span class="line">        <span class="comment">// cause.printStackTrace();</span></span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>clientHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client4HeatbeatHandler</span> <span class="keyword">extends</span> <span class="title">ChannelHandlerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> ScheduledExecutorService executorService = Executors.newScheduledThreadPool(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">private</span> ScheduledFuture heatbeat;</span><br><span class="line">    <span class="keyword">private</span> InetAddress remoteAddr;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String HEATBEAT_SUCCESS = <span class="string">"SERVER_RETURN_HEATBEAT_SUCCESS"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//只运行一次</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelActive</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">// 获取本地INET信息</span></span><br><span class="line">        <span class="keyword">this</span>.remoteAddr = InetAddress.getLocalHost();</span><br><span class="line">        <span class="comment">// 获取本地计算机名</span></span><br><span class="line">        String computerName = System.getenv().get(<span class="string">"COMPUTERNAME"</span>);</span><br><span class="line">        String credentials = <span class="keyword">this</span>.remoteAddr.getHostAddress() + <span class="string">"_"</span> + computerName;</span><br><span class="line">        System.out.println(credentials);</span><br><span class="line">        <span class="comment">// 发送到服务器，作为信息比对证书</span></span><br><span class="line">        ctx.writeAndFlush(credentials);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(msg <span class="keyword">instanceof</span> String)&#123;</span><br><span class="line">                <span class="keyword">if</span>(HEATBEAT_SUCCESS.equals(msg))&#123;</span><br><span class="line">                    <span class="keyword">this</span>.heatbeat = <span class="keyword">this</span>.executorService.scheduleWithFixedDelay(<span class="keyword">new</span> HeatbeatTask(ctx), <span class="number">0L</span>, <span class="number">2L</span>, TimeUnit.SECONDS);</span><br><span class="line">                    System.out.println(<span class="string">"client receive - "</span> + msg);</span><br><span class="line">                &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                    System.out.println(<span class="string">"client receive - "</span> + msg);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line">            ReferenceCountUtil.release(msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"client exceptionCaught method run..."</span>);</span><br><span class="line">        <span class="comment">// cause.printStackTrace();</span></span><br><span class="line">        <span class="comment">// 回收资源</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.heatbeat != <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">this</span>.heatbeat.cancel(<span class="keyword">true</span>);</span><br><span class="line">            <span class="keyword">this</span>.heatbeat = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">HeatbeatTask</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> ChannelHandlerContext ctx;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">HeatbeatTask</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">HeatbeatTask</span><span class="params">(ChannelHandlerContext ctx)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.ctx = ctx;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                HeatbeatMessage msg = <span class="keyword">new</span> HeatbeatMessage();</span><br><span class="line">                msg.setIp(remoteAddr.getHostAddress());</span><br><span class="line">                Sigar sigar = <span class="keyword">new</span> Sigar();</span><br><span class="line">                <span class="comment">// CPU信息</span></span><br><span class="line">                CpuPerc cpuPerc = sigar.getCpuPerc();</span><br><span class="line">                Map&lt;String, Object&gt; cpuMsgMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">                cpuMsgMap.put(<span class="string">"Combined"</span>, cpuPerc.getCombined());</span><br><span class="line">                cpuMsgMap.put(<span class="string">"User"</span>, cpuPerc.getUser());</span><br><span class="line">                cpuMsgMap.put(<span class="string">"Sys"</span>, cpuPerc.getSys());</span><br><span class="line">                cpuMsgMap.put(<span class="string">"Wait"</span>, cpuPerc.getWait());</span><br><span class="line">                cpuMsgMap.put(<span class="string">"Idle"</span>, cpuPerc.getIdle());</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 内存信息</span></span><br><span class="line">                Map&lt;String, Object&gt; memMsgMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">                Mem mem = sigar.getMem();</span><br><span class="line">                memMsgMap.put(<span class="string">"Total"</span>, mem.getTotal());</span><br><span class="line">                memMsgMap.put(<span class="string">"Used"</span>, mem.getUsed());</span><br><span class="line">                memMsgMap.put(<span class="string">"Free"</span>, mem.getFree());</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 文件系统</span></span><br><span class="line">                Map&lt;String, Object&gt; fileSysMsgMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">                FileSystem[] list = sigar.getFileSystemList();</span><br><span class="line">                fileSysMsgMap.put(<span class="string">"FileSysCount"</span>, list.length);</span><br><span class="line">                List&lt;String&gt; msgList = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">for</span>(FileSystem fs : list)&#123;</span><br><span class="line">                    msgList = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">                    msgList.add(fs.getDevName() + <span class="string">"总大小:    "</span> + sigar.getFileSystemUsage(fs.getDirName()).getTotal() + <span class="string">"KB"</span>);</span><br><span class="line">                    msgList.add(fs.getDevName() + <span class="string">"剩余大小:    "</span> + sigar.getFileSystemUsage(fs.getDirName()).getFree() + <span class="string">"KB"</span>);</span><br><span class="line">                    fileSysMsgMap.put(fs.getDevName(), msgList);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                msg.setCpuMsgMap(cpuMsgMap);</span><br><span class="line">                msg.setMemMsgMap(memMsgMap);</span><br><span class="line">                msg.setFileSysMsgMap(fileSysMsgMap);</span><br><span class="line"></span><br><span class="line">                ctx.writeAndFlush(msg);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><strong>HTTP</strong> <strong>协议处理</strong> ：使用 <em>Netty</em> 服务开发。实现 <em>HTTP</em> 协议处理逻辑。 没有客户端，做一个http协议文件传输到netty服务器</li>
</ul>
<p>server</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment"> * http协议文件传输 </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Qixuan.Chen </span></span><br><span class="line"><span class="comment"> * 创建时间：2015年5月4日 </span></span><br><span class="line"><span class="comment"> */</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpStaticFileServer</span> </span>&#123;  </span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> port;<span class="comment">//端口  </span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HttpStaticFileServer</span><span class="params">(<span class="keyword">int</span> port)</span> </span>&#123;  </span><br><span class="line">        <span class="keyword">this</span>.port = port;  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;  </span><br><span class="line">        EventLoopGroup bossGroup = <span class="keyword">new</span> NioEventLoopGroup();<span class="comment">//线程一 //这个是用于serversocketchannel的event  </span></span><br><span class="line">        EventLoopGroup workerGroup = <span class="keyword">new</span> NioEventLoopGroup();<span class="comment">//线程二//这个是用于处理accept到的channel  </span></span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            ServerBootstrap b = <span class="keyword">new</span> ServerBootstrap();  </span><br><span class="line">            b.group(bossGroup, workerGroup)  </span><br><span class="line">             .channel(NioServerSocketChannel.class)  </span><br><span class="line">             .childHandler(<span class="keyword">new</span> HttpStaticFileServerInitializer());  </span><br><span class="line"></span><br><span class="line">            b.bind(port).sync().channel().closeFuture().sync();  </span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;  </span><br><span class="line">            bossGroup.shutdownGracefully();  </span><br><span class="line">            workerGroup.shutdownGracefully();  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;  </span><br><span class="line">        <span class="keyword">int</span> port = <span class="number">8089</span>;  </span><br><span class="line">        <span class="keyword">if</span> (args.length &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">            port = Integer.parseInt(args[<span class="number">0</span>]);  </span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">            port = <span class="number">8089</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">new</span> HttpStaticFileServer(port).run();<span class="comment">//启动服务  </span></span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpStaticFileServerInitializer</span> <span class="keyword">extends</span> <span class="title">ChannelInitializer</span>&lt;<span class="title">SocketChannel</span>&gt; </span>&#123;  </span><br><span class="line">    <span class="meta">@Override</span>  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception </span>&#123;  </span><br><span class="line">        <span class="comment">// Create a default pipeline implementation.</span></span><br><span class="line">        <span class="comment">// 通道的连接点</span></span><br><span class="line">        ChannelPipeline pipeline = ch.pipeline();  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Uncomment the following line if you want HTTPS  </span></span><br><span class="line">        <span class="comment">//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();  </span></span><br><span class="line">        <span class="comment">//engine.setUseClientMode(false);  </span></span><br><span class="line">        <span class="comment">//pipeline.addLast("ssl", new SslHandler(engine));  </span></span><br><span class="line">       <span class="comment">/** </span></span><br><span class="line"><span class="comment">        *   （1）ReadTimeoutHandler，用于控制读取数据的时候的超时，10表示如果10秒钟都没有数据读取了，那么就引发超时，然后关闭当前的channel </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">            （2）WriteTimeoutHandler，用于控制数据输出的时候的超时，构造参数1表示如果持续1秒钟都没有数据写了，那么就超时。 </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">            （3）HttpRequestrianDecoder，这个handler用于从读取的数据中将http报文信息解析出来，无非就是什么requestline，header，body什么的。。。 </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">            （4）然后HttpObjectAggregator则是用于将上卖解析出来的http报文的数据组装成为封装好的httprequest对象。。 </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">            （5）HttpresponseEncoder，用于将用户返回的httpresponse编码成为http报文格式的数据 </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">            （6）HttpHandler，自定义的handler，用于处理接收到的http请求。 </span></span><br><span class="line"><span class="comment">        */</span>  </span><br><span class="line"></span><br><span class="line">        pipeline.addLast(<span class="string">"decoder"</span>, <span class="keyword">new</span> HttpRequestDecoder());<span class="comment">// http-request解码器,http服务器端对request解码  </span></span><br><span class="line">        pipeline.addLast(<span class="string">"aggregator"</span>, <span class="keyword">new</span> HttpObjectAggregator(<span class="number">65536</span>));<span class="comment">//对传输文件大少进行限制  </span></span><br><span class="line">        pipeline.addLast(<span class="string">"encoder"</span>, <span class="keyword">new</span> HttpResponseEncoder());<span class="comment">//http-response解码器,http服务器端对response编码  </span></span><br><span class="line">        <span class="comment">// 向客户端发送数据的一个Handler</span></span><br><span class="line">        pipeline.addLast(<span class="string">"chunkedWriter"</span>, <span class="keyword">new</span> ChunkedWriteHandler());  </span><br><span class="line"></span><br><span class="line">        pipeline.addLast(<span class="string">"handler"</span>, <span class="keyword">new</span> HttpStaticFileServerHandler(<span class="keyword">true</span>)); <span class="comment">// Specify false if SSL.(如果是ssl,就指定为false)  </span></span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>serverHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HttpStaticFileServerHandler</span> <span class="keyword">extends</span> <span class="title">SimpleChannelInboundHandler</span>&lt;<span class="title">FullHttpRequest</span>&gt; </span>&#123;  </span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String HTTP_DATE_FORMAT = <span class="string">"EEE, dd MMM yyyy HH:mm:ss zzz"</span>;  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String HTTP_DATE_GMT_TIMEZONE = <span class="string">"GMT"</span>;  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> HTTP_CACHE_SECONDS = <span class="number">60</span>;  </span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> useSendFile;  </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HttpStaticFileServerHandler</span><span class="params">(<span class="keyword">boolean</span> useSendFile)</span> </span>&#123;  </span><br><span class="line">        <span class="keyword">this</span>.useSendFile = useSendFile;  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 类似channelRead方法。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span>  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">messageReceived</span><span class="params">(  </span></span></span><br><span class="line"><span class="function"><span class="params">            ChannelHandlerContext ctx, FullHttpRequest request)</span> <span class="keyword">throws</span> Exception </span>&#123;  </span><br><span class="line">        <span class="comment">// 请求头信息是否正确的</span></span><br><span class="line">        <span class="keyword">if</span> (!request.decoderResult().isSuccess()) &#123;  </span><br><span class="line">            sendError(ctx, BAD_REQUEST);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (request.method() != GET) &#123;  </span><br><span class="line">            sendError(ctx, METHOD_NOT_ALLOWED);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">final</span> String uri = request.uri();  </span><br><span class="line">        System.out.println(<span class="string">"-----uri----"</span>+uri);  </span><br><span class="line">        <span class="keyword">final</span> String path = sanitizeUri(uri);  </span><br><span class="line">        System.out.println(<span class="string">"-----path----"</span>+path);  </span><br><span class="line">        <span class="keyword">if</span> (path == <span class="keyword">null</span>) &#123;  </span><br><span class="line">            sendError(ctx, FORBIDDEN);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        File file = <span class="keyword">new</span> File(path);  </span><br><span class="line">        <span class="keyword">if</span> (file.isHidden() || !file.exists()) &#123;  </span><br><span class="line">            sendError(ctx, NOT_FOUND);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (file.isDirectory()) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (uri.endsWith(<span class="string">"/"</span>)) &#123;  </span><br><span class="line">                sendListing(ctx, file);  </span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">                sendRedirect(ctx, uri + <span class="string">'/'</span>);  </span><br><span class="line">            &#125;  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!file.isFile()) &#123;  </span><br><span class="line">            sendError(ctx, FORBIDDEN);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Cache Validation  </span></span><br><span class="line">        String ifModifiedSince = (String) request.headers().get(IF_MODIFIED_SINCE);  </span><br><span class="line">        <span class="keyword">if</span> (ifModifiedSince != <span class="keyword">null</span> &amp;&amp; !ifModifiedSince.isEmpty()) &#123;  </span><br><span class="line">            SimpleDateFormat dateFormatter = <span class="keyword">new</span> SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);  </span><br><span class="line">            Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);  </span><br><span class="line"></span><br><span class="line">            <span class="comment">// Only compare up to the second because the datetime format we send to the client  </span></span><br><span class="line">            <span class="comment">// does not have milliseconds  </span></span><br><span class="line">            <span class="keyword">long</span> ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / <span class="number">1000</span>;  </span><br><span class="line">            <span class="keyword">long</span> fileLastModifiedSeconds = file.lastModified() / <span class="number">1000</span>;  </span><br><span class="line">            <span class="keyword">if</span> (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) &#123;  </span><br><span class="line">                sendNotModified(ctx);  </span><br><span class="line">                <span class="keyword">return</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">          <span class="comment">// 文件下载</span></span><br><span class="line">        RandomAccessFile raf;  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            raf = <span class="keyword">new</span> RandomAccessFile(file, <span class="string">"r"</span>);  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (FileNotFoundException fnfe) &#123;  </span><br><span class="line">            sendError(ctx, NOT_FOUND);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">long</span> fileLength = raf.length();  </span><br><span class="line"></span><br><span class="line">        HttpResponse response = <span class="keyword">new</span> DefaultHttpResponse(HTTP_1_1, OK);  </span><br><span class="line">        <span class="comment">//setContentLength(response, fileLength);  </span></span><br><span class="line">        HttpHeaderUtil.setContentLength(response, fileLength);</span><br><span class="line">        setContentTypeHeader(response, file);  </span><br><span class="line">        setDateAndCacheHeaders(response, file);  </span><br><span class="line">        <span class="keyword">if</span> (HttpHeaderUtil.isKeepAlive(request)) &#123;</span><br><span class="line"></span><br><span class="line">            response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Write the initial line and the header.  </span></span><br><span class="line">        ctx.write(response);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Write the content.  </span></span><br><span class="line">        ChannelFuture sendFileFuture;  </span><br><span class="line">        <span class="keyword">if</span> (useSendFile) &#123;  </span><br><span class="line">            sendFileFuture =  </span><br><span class="line">                    ctx.write(<span class="keyword">new</span> DefaultFileRegion(raf.getChannel(), <span class="number">0</span>, fileLength), ctx.newProgressivePromise());  </span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">            sendFileFuture =  </span><br><span class="line">                    ctx.write(<span class="keyword">new</span> ChunkedFile(raf, <span class="number">0</span>, fileLength, <span class="number">8192</span>), ctx.newProgressivePromise());  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        sendFileFuture.addListener(<span class="keyword">new</span> ChannelProgressiveFutureListener() &#123;  </span><br><span class="line">            <span class="meta">@Override</span>  </span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">operationProgressed</span><span class="params">(ChannelProgressiveFuture future, <span class="keyword">long</span> progress, <span class="keyword">long</span> total)</span> </span>&#123;  </span><br><span class="line">                <span class="keyword">if</span> (total &lt; <span class="number">0</span>) &#123; <span class="comment">// total unknown  </span></span><br><span class="line">                    System.err.println(<span class="string">"Transfer progress: "</span> + progress);  </span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">                    System.err.println(<span class="string">"Transfer progress: "</span> + progress + <span class="string">" / "</span> + total);  </span><br><span class="line">                &#125;  </span><br><span class="line">            &#125;  </span><br><span class="line"></span><br><span class="line">            <span class="meta">@Override</span>  </span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">operationComplete</span><span class="params">(ChannelProgressiveFuture future)</span> <span class="keyword">throws</span> Exception </span>&#123;  </span><br><span class="line">                System.err.println(<span class="string">"Transfer complete."</span>);  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Write the end marker  </span></span><br><span class="line">        ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Decide whether to close the connection or not.  </span></span><br><span class="line">        <span class="keyword">if</span> (!HttpHeaderUtil.isKeepAlive(request)) &#123;  </span><br><span class="line">            <span class="comment">// Close the connection when the whole content is written out.  </span></span><br><span class="line">            lastContentFuture.addListener(ChannelFutureListener.CLOSE);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span>  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> <span class="keyword">throws</span> Exception </span>&#123;  </span><br><span class="line">        cause.printStackTrace();  </span><br><span class="line">        <span class="keyword">if</span> (ctx.channel().isActive()) &#123;  </span><br><span class="line">            sendError(ctx, INTERNAL_SERVER_ERROR);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Pattern INSECURE_URI = Pattern.compile(<span class="string">".*[&lt;&gt;&amp;\"].*"</span>);  </span><br><span class="line"></span><br><span class="line">    <span class="comment">/** </span></span><br><span class="line"><span class="comment">     * 路径解码 </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> uri </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> String <span class="title">sanitizeUri</span><span class="params">(String uri)</span> </span>&#123;  </span><br><span class="line">        <span class="comment">// Decode the path.  </span></span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            uri = URLDecoder.decode(uri, <span class="string">"UTF-8"</span>);  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (UnsupportedEncodingException e) &#123;  </span><br><span class="line">            <span class="keyword">try</span> &#123;  </span><br><span class="line">                uri = URLDecoder.decode(uri, <span class="string">"ISO-8859-1"</span>);  </span><br><span class="line">            &#125; <span class="keyword">catch</span> (UnsupportedEncodingException e1) &#123;  </span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> Error();  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!uri.startsWith(<span class="string">"/"</span>)) &#123;  </span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Convert file separators.  </span></span><br><span class="line">        uri = uri.replace(<span class="string">'/'</span>, File.separatorChar);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Simplistic dumb security check.  </span></span><br><span class="line">        <span class="comment">// You will have to do something serious in the production environment.  </span></span><br><span class="line">        <span class="keyword">if</span> (uri.contains(File.separator + <span class="string">'.'</span>) ||  </span><br><span class="line">            uri.contains(<span class="string">'.'</span> + File.separator) ||  </span><br><span class="line">            uri.startsWith(<span class="string">"."</span>) || uri.endsWith(<span class="string">"."</span>) ||  </span><br><span class="line">            INSECURE_URI.matcher(uri).matches()) &#123;  </span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Convert to absolute path.  </span></span><br><span class="line">        <span class="keyword">return</span> System.getProperty(<span class="string">"user.dir"</span>) + File.separator + uri;  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Pattern ALLOWED_FILE_NAME = Pattern.compile(<span class="string">"[A-Za-z0-9][-_A-Za-z0-9\\.]*"</span>);  </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sendListing</span><span class="params">(ChannelHandlerContext ctx, File dir)</span> </span>&#123;  </span><br><span class="line">        FullHttpResponse response = <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1, OK);  </span><br><span class="line">        response.headers().set(CONTENT_TYPE, <span class="string">"text/html; charset=UTF-8"</span>);  </span><br><span class="line"></span><br><span class="line">        StringBuilder buf = <span class="keyword">new</span> StringBuilder();  </span><br><span class="line">        String dirPath = dir.getPath();  </span><br><span class="line"></span><br><span class="line">        buf.append(<span class="string">"&lt;!DOCTYPE html&gt;\r\n"</span>);  </span><br><span class="line">        buf.append(<span class="string">"&lt;html&gt;&lt;head&gt;&lt;title&gt;"</span>);  </span><br><span class="line">        buf.append(<span class="string">"Listing of: "</span>);  </span><br><span class="line">        buf.append(dirPath);  </span><br><span class="line">        buf.append(<span class="string">"&lt;/title&gt;&lt;/head&gt;&lt;body&gt;\r\n"</span>);  </span><br><span class="line"></span><br><span class="line">        buf.append(<span class="string">"&lt;h3&gt;Listing of: "</span>);  </span><br><span class="line">        buf.append(dirPath);  </span><br><span class="line">        buf.append(<span class="string">"&lt;/h3&gt;\r\n"</span>);  </span><br><span class="line"></span><br><span class="line">        buf.append(<span class="string">"&lt;ul&gt;"</span>);  </span><br><span class="line">        buf.append(<span class="string">"&lt;li&gt;&lt;a href=\"../\"&gt;..&lt;/a&gt;&lt;/li&gt;\r\n"</span>);  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (File f: dir.listFiles()) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (f.isHidden() || !f.canRead()) &#123;  </span><br><span class="line">                <span class="keyword">continue</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line"></span><br><span class="line">            String name = f.getName();  </span><br><span class="line">            <span class="keyword">if</span> (!ALLOWED_FILE_NAME.matcher(name).matches()) &#123;  </span><br><span class="line">                <span class="keyword">continue</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line"></span><br><span class="line">            buf.append(<span class="string">"&lt;li&gt;&lt;a href=\""</span>);  </span><br><span class="line">            buf.append(name);  </span><br><span class="line">            buf.append(<span class="string">"\"&gt;"</span>);  </span><br><span class="line">            buf.append(name);  </span><br><span class="line">            buf.append(<span class="string">"&lt;/a&gt;&lt;/li&gt;\r\n"</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line"></span><br><span class="line">        buf.append(<span class="string">"&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;\r\n"</span>);  </span><br><span class="line">        ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);  </span><br><span class="line">        response.content().writeBytes(buffer);  </span><br><span class="line">        buffer.release();  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Close the connection as soon as the error message is sent.  </span></span><br><span class="line">        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sendRedirect</span><span class="params">(ChannelHandlerContext ctx, String newUri)</span> </span>&#123;  </span><br><span class="line">        FullHttpResponse response = <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1, FOUND);  </span><br><span class="line">        response.headers().set(LOCATION, newUri);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Close the connection as soon as the error message is sent.  </span></span><br><span class="line">        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sendError</span><span class="params">(ChannelHandlerContext ctx, HttpResponseStatus status)</span> </span>&#123;  </span><br><span class="line">        FullHttpResponse response = <span class="keyword">new</span> DefaultFullHttpResponse(  </span><br><span class="line">                HTTP_1_1, status, Unpooled.copiedBuffer(<span class="string">"Failure: "</span> + status.toString() + <span class="string">"\r\n"</span>, CharsetUtil.UTF_8));  </span><br><span class="line">        response.headers().set(CONTENT_TYPE, <span class="string">"text/plain; charset=UTF-8"</span>);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Close the connection as soon as the error message is sent.  </span></span><br><span class="line">        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="comment">/** </span></span><br><span class="line"><span class="comment">     * When file timestamp is the same as what the browser is sending up, send a "304 Not Modified" </span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ctx </span></span><br><span class="line"><span class="comment">     *            Context </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sendNotModified</span><span class="params">(ChannelHandlerContext ctx)</span> </span>&#123;  </span><br><span class="line">        FullHttpResponse response = <span class="keyword">new</span> DefaultFullHttpResponse(HTTP_1_1, NOT_MODIFIED);  </span><br><span class="line">        setDateHeader(response);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Close the connection as soon as the error message is sent.  </span></span><br><span class="line">        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="comment">/** </span></span><br><span class="line"><span class="comment">     * Sets the Date header for the HTTP response </span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> response </span></span><br><span class="line"><span class="comment">     *            HTTP response </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setDateHeader</span><span class="params">(FullHttpResponse response)</span> </span>&#123;  </span><br><span class="line">        SimpleDateFormat dateFormatter = <span class="keyword">new</span> SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);  </span><br><span class="line">        dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));  </span><br><span class="line"></span><br><span class="line">        Calendar time = <span class="keyword">new</span> GregorianCalendar();  </span><br><span class="line">        response.headers().set(DATE, dateFormatter.format(time.getTime()));  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="comment">/** </span></span><br><span class="line"><span class="comment">     * Sets the Date and Cache headers for the HTTP Response </span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> response </span></span><br><span class="line"><span class="comment">     *            HTTP response </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fileToCache </span></span><br><span class="line"><span class="comment">     *            file to extract content type </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setDateAndCacheHeaders</span><span class="params">(HttpResponse response, File fileToCache)</span> </span>&#123;  </span><br><span class="line">        SimpleDateFormat dateFormatter = <span class="keyword">new</span> SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);  </span><br><span class="line">        dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Date header  </span></span><br><span class="line">        Calendar time = <span class="keyword">new</span> GregorianCalendar();  </span><br><span class="line">        response.headers().set(DATE, dateFormatter.format(time.getTime()));  </span><br><span class="line"></span><br><span class="line">        <span class="comment">// Add cache headers  </span></span><br><span class="line">        time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);  </span><br><span class="line">        response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));  </span><br><span class="line">        response.headers().set(CACHE_CONTROL, <span class="string">"private, max-age="</span> + HTTP_CACHE_SECONDS);  </span><br><span class="line">        response.headers().set(  </span><br><span class="line">                LAST_MODIFIED, dateFormatter.format(<span class="keyword">new</span> Date(fileToCache.lastModified())));  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">    <span class="comment">/** </span></span><br><span class="line"><span class="comment">     * Sets the content type header for the HTTP Response </span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> response </span></span><br><span class="line"><span class="comment">     *            HTTP response </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> file </span></span><br><span class="line"><span class="comment">     *            file to extract content type </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setContentTypeHeader</span><span class="params">(HttpResponse response, File file)</span> </span>&#123;  </span><br><span class="line">        MimetypesFileTypeMap mimeTypesMap = <span class="keyword">new</span> MimetypesFileTypeMap();  </span><br><span class="line">        response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));  </span><br><span class="line">    &#125;  </span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>流数据的传输处理</strong> </p>
<p>​        在基于流的传输里比如 <em>TCP/IP</em>，接收到的数据会先被存储到一个 <em>socket</em> 接收缓冲里。不 幸的是，基于流的传输并不是一个数据包队列，而是一个字节队列。即使你发送了 <em>2</em> 个独立 的数据包，操作系统也不会作为 <em>2</em> 个消息处理而仅仅是作为一连串的字节而言。因此这是不 能保证你远程写入的数据就会准确地读取。所以一个接收方不管他是客户端还是服务端，都 应该把接收到的数据整理成一个或者多个更有意思并且能够让程序的业务逻辑更好理解的 数据。 </p>
<p>在处理流数据粘包拆包时，可以使用下述处理方式： </p>
<p>使用定长数据处理，如：每个完整请求数据长度为 <em>8</em> 字节等。（<em>FixedLengthFrameDecoder</em>） </p>
<p>使用特殊分隔符的方式处理，如：每个完整请求数据末尾使用<em>’\0’</em>作为数据结束标记。（<em>DelimiterBasedFrameDecoder</em>） </p>
<p>使用自定义协议方式处理，如：<em>http</em> 协议格式等。 </p>
<p>使用 <em>POJO</em> 来替代传递的流数据，如：每个完整的请求数据都是一个 <em>RequestMessage</em> 对象，在 <em>Java</em> 语言中，使用 <em>POJO</em> 更符合语种特性，推荐使用。</p>
<p>转载至微信公众号《Java患者》。</p>

      
    </div>

    

    
    
    

    

    
      
    
    

    

    <footer class="post-footer">
      
        
          
        
        <div class="post-tags">
          
            <a href="/tags/并发和多线程/" rel="tag"><i class="fa fa-tag"></i> 并发和多线程</a>
          
        </div>
      

      
      
        <div class="post-widgets">
        

        

        
          
          <div class="social_share">
            
              <div>
                

<script src="//cdn.jsdelivr.net/npm/ilyabirman-likely@2/release/likely.js"></script>



<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/ilyabirman-likely@2/release/likely.css">


  


<div class="likely likely-light">
	
 	 	<div class="twitter">Tweet</div>
	
 	 	<div class="facebook">Share</div>
	
 	 	<div class="linkedin">Link</div>
	
 	 	<div class="gplus">Plus</div>
	
 	 	<div class="vkontakte">Share</div>
	
 	 	<div class="odnoklassniki">Class</div>
	
 	 	<div class="telegram">Send</div>
	
 	 	<div class="whatsapp">Send</div>
	
 	 	<div class="pinterest">Pin</div>
	
</div>

              </div>
            
            
            
              <div>
                
  <div class="bdsharebuttonbox">
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
    <a href="#" class="bds_douban" data-cmd="douban" title="分享到豆瓣网"></a>
    <a href="#" class="bds_sqq" data-cmd="sqq" title="分享到QQ好友"></a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a>
    <a href="#" class="bds_tieba" data-cmd="tieba" title="分享到百度贴吧"></a>
    <a href="#" class="bds_twi" data-cmd="twi" title="分享到Twitter"></a>
    <a href="#" class="bds_fbook" data-cmd="fbook" title="分享到Facebook"></a>
    <a href="#" class="bds_more" data-cmd="more"></a>
    <a class="bds_count" data-cmd="count"></a>
  </div>
  <script>
    window._bd_share_config = {
      "common": {
        "bdText": "",
        "bdMini": "2",
        "bdMiniList": false,
        "bdPic": ""
      },
      "share": {
        "bdSize": "16",
        "bdStyle": "0"
      },
      "image": {
        "viewList": ["tsina", "douban", "sqq", "qzone", "weixin", "twi", "fbook"],
        "viewText": "分享到：",
        "viewSize": "16"
      }
    }
  </script>

<script>
  with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='//bdimg.share.baidu.com/static/api/js/share.js?cdnversion='+~(-new Date()/36e5)];
</script>

              </div>
            
          </div>
        
        </div>
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/关于fastjson解析后的属性排序问题解决方案.html" rel="next" title="关于fastjson解析后的属性排序问题解决方案">
                <i class="fa fa-chevron-left"></i> 关于fastjson解析后的属性排序问题解决方案
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/一次Java线程池误用引发的血案和总结.html" rel="prev" title="一次Java线程池误用引发的血案和总结">
                一次Java线程池误用引发的血案和总结 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>


  </div>


          </div>
          

  
    <div class="comments" id="comments">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8yOTk3My82NTM4"></div>
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image" src="https://hexoblog-1254111960.cos.ap-guangzhou.myqcloud.com/HexoBlog-tou.jpg" alt="Daniel X">
            
              <p class="site-author-name" itemprop="name">Daniel X</p>
              <div class="site-description motion-element" itemprop="description">專注于大数据技術，分享干货</div>
          </div>

          
            <nav class="site-state motion-element">
              
                <div class="site-state-item site-state-posts">
                
                  <a href="/archives/">
                
                    <span class="site-state-item-count">125</span>
                    <span class="site-state-item-name">日志</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-categories">
                  
                    
                      <a href="/categories">
                    
                  
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">15</span>
                    <span class="site-state-item-name">分类</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-tags">
                  
                    
                      <a href="/tags">
                    
                  
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">63</span>
                    <span class="site-state-item-name">标签</span>
                  </a>
                </div>
              
            </nav>
          

          

          

          
            <div class="links-of-author motion-element">
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2R1ZGVmdQ==" title="GitHub &rarr; https://github.com/dudefu"><i class="fa fa-fw fa-github"></i>GitHub</span>
                </span>
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <span class="exturl" data-url="bWFpbHRvOmR1ZGVmdUBmb3htYWlsLmNvbT9zdWJqZWN0PUhlbGxvJTIwYWdhaW4=" title="E-mail &rarr; mailto:dudefu@foxmail.com?subject=Hello%20again"><i class="fa fa-fw fa-envelope"></i>E-mail</span>
                </span>
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <span class="exturl" data-url="aHR0cHM6Ly93ZWliby5jb20vZHVkZWZ1" title="Weibo &rarr; https://weibo.com/dudefu"><i class="fa fa-fw fa-weibo"></i>Weibo</span>
                </span>
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <span class="exturl" data-url="aHR0cHM6Ly93cGEucXEuY29tL21zZ3JkP3Y9MyZ1aW49MTU3NzU3MTk1OSZzaXRlPWR1ZGVmdS5pbmZvJm1lbnU9eWVz" title="QQ &rarr; https://wpa.qq.com/msgrd?v=3&uin=1577571959&site=dudefu.info&menu=yes"><i class="fa fa-fw fa-qq"></i>QQ</span>
                </span>
              
            </div>
          

          

          
          

          
            
          
          

        </div>
      </div>

      
      <!--noindex-->
        <div class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
            
            
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#练气期（并发编程基础）"><span class="nav-number">1.</span> <span class="nav-text">练气期（并发编程基础）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期一层（this）"><span class="nav-number">1.1.</span> <span class="nav-text">练气期一层（this）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期二层（static）"><span class="nav-number">1.2.</span> <span class="nav-text">练气期二层（static）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期三层（原子性）"><span class="nav-number">1.3.</span> <span class="nav-text">练气期三层（原子性）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期四层（同步与非同步方法间调用）"><span class="nav-number">1.4.</span> <span class="nav-text">练气期四层（同步与非同步方法间调用）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期五层（存在原子性问题）"><span class="nav-number">1.5.</span> <span class="nav-text">练气期五层（存在原子性问题）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期六层（锁可重入）"><span class="nav-number">1.6.</span> <span class="nav-text">练气期六层（锁可重入）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期七层（调用父类的同步方法）"><span class="nav-number">1.7.</span> <span class="nav-text">练气期七层（调用父类的同步方法）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期八层（锁与异常）"><span class="nav-number">1.8.</span> <span class="nav-text">练气期八层（锁与异常）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期九层（volatile）"><span class="nav-number">1.9.</span> <span class="nav-text">练气期九层（volatile）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期十层（AtomicXxx）"><span class="nav-number">1.10.</span> <span class="nav-text">练气期十层（AtomicXxx）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期十一层（锁对象变更）"><span class="nav-number">1.11.</span> <span class="nav-text">练气期十一层（锁对象变更）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期十二层（CountDownLatch）"><span class="nav-number">1.12.</span> <span class="nav-text">练气期十二层（CountDownLatch）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#练气期大圆满"><span class="nav-number">1.13.</span> <span class="nav-text">练气期大圆满</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#筑基期（ReentrantLock）"><span class="nav-number">2.</span> <span class="nav-text">筑基期（ReentrantLock）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#筑基初期（lock等待锁）"><span class="nav-number">2.1.</span> <span class="nav-text">筑基初期（lock等待锁）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#筑基中期（tryLock尝试锁）"><span class="nav-number">2.2.</span> <span class="nav-text">筑基中期（tryLock尝试锁）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#筑基后期（lockInterruptibly可打断锁）"><span class="nav-number">2.3.</span> <span class="nav-text">筑基后期（lockInterruptibly可打断锁）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#筑基圆满（公平锁）"><span class="nav-number">2.4.</span> <span class="nav-text">筑基圆满（公平锁）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#金丹期"><span class="nav-number">3.</span> <span class="nav-text">金丹期</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#金丹初期（生产者-amp-消费者）"><span class="nav-number">3.1.</span> <span class="nav-text">金丹初期（生产者&amp;消费者）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#金丹中期（锁的底层实现）"><span class="nav-number">3.2.</span> <span class="nav-text">金丹中期（锁的底层实现）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#金丹后期（锁的种类）"><span class="nav-number">3.3.</span> <span class="nav-text">金丹后期（锁的种类）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#金丹圆满（ThreadLocal）"><span class="nav-number">3.4.</span> <span class="nav-text">金丹圆满（ThreadLocal）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#元婴期（并发容器）"><span class="nav-number">4.</span> <span class="nav-text">元婴期（并发容器）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#元婴前期（Map-Set）"><span class="nav-number">4.1.</span> <span class="nav-text">元婴前期（Map/Set）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#元婴中期（List）"><span class="nav-number">4.2.</span> <span class="nav-text">元婴中期（List）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#元婴后期（Queue）"><span class="nav-number">4.3.</span> <span class="nav-text">元婴后期（Queue）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#元婴圆满（线程池）"><span class="nav-number">4.4.</span> <span class="nav-text">元婴圆满（线程池）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#化神期（JVM1-7）"><span class="nav-number">5.</span> <span class="nav-text">化神期（JVM1.7）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#化神前期（jvm结构）"><span class="nav-number">5.1.</span> <span class="nav-text">化神前期（jvm结构）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#化神中期（堆结构及对象分代）"><span class="nav-number">5.2.</span> <span class="nav-text">化神中期（堆结构及对象分代）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#化神后期（垃圾回收算法及分代垃圾）"><span class="nav-number">5.3.</span> <span class="nav-text">化神后期（垃圾回收算法及分代垃圾）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#化神圆满（JVM优化）"><span class="nav-number">5.4.</span> <span class="nav-text">化神圆满（JVM优化）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#合体期（网络编程）"><span class="nav-number">6.</span> <span class="nav-text">合体期（网络编程）</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#合体前期（Socket）"><span class="nav-number">6.1.</span> <span class="nav-text">合体前期（Socket）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#合体中期（BIO、NIO-、AIO）"><span class="nav-number">6.2.</span> <span class="nav-text">合体中期（BIO、NIO 、AIO）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#合体后期（Netty）"><span class="nav-number">6.3.</span> <span class="nav-text">合体后期（Netty）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#合体圆满（基础代码演示）"><span class="nav-number">6.4.</span> <span class="nav-text">合体圆满（基础代码演示）</span></a></li></ol></li></ol></div>
            

          </div>
        </div>
      <!--/noindex-->
      

      

    </div>
  </aside>
  


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">  <span class="exturl" data-url="aHR0cDovL3d3dy5iZWlhbi5taWl0Lmdvdi5jbg==">粤ICP备18110871号 </span>&copy; 2017 – <span itemprop="copyrightYear">2021</span>
  <span class="with-love" id="animate">
    <i class="fa fa-spinner"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">dudefu</span>

  

  
</div>

<!--

  <div class="powered-by">由 <span class="exturl theme-link" data-url="aHR0cHM6Ly9oZXhvLmlv">Hexo</span> 强力驱动 v3.8.0</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 – <span class="exturl theme-link" data-url="aHR0cHM6Ly90aGVtZS1uZXh0Lm9yZw==">NexT.Pisces</span> v7.1.2</div>

-->



        








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
          <span id="scrollpercent"><span>0</span>%</span>
        
      </div>
    

    

    

    
  </div>

  

<script>
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>














  
    
    
      
    
  
  <script color="26,26,26" opacity="0.5" zindex="-1" count="99" src="//cdn.jsdelivr.net/gh/theme-next/theme-next-canvas-nest@1/canvas-nest.min.js"></script>









  
  
  <script id="ribbon" size="300" alpha="0.6" zindex="-1" src="/lib/canvas-ribbon/canvas-ribbon.js"></script>



  



  
  <script src="/lib/jquery/index.js?v=3.4.1"></script>

  
  <script src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script src="/lib/reading_progress/reading_progress.js"></script>


  


  <script src="/js/utils.js?v=7.1.2"></script>

  <script src="/js/motion.js?v=7.1.2"></script>



  
  


  <script src="/js/affix.js?v=7.1.2"></script>

  <script src="/js/schemes/pisces.js?v=7.1.2"></script>



  
  <script src="/js/scrollspy.js?v=7.1.2"></script>
<script src="/js/post-details.js?v=7.1.2"></script>



  


  <script src="/js/next-boot.js?v=7.1.2"></script>


  
  <script src="/js/js.cookie.js?v=7.1.2"></script>
  <script src="/js/scroll-cookie.js?v=7.1.2"></script>


  
  <script src="/js/exturl.js?v=7.1.2"></script>


  

  
  

<script src="//cdn1.lncld.net/static/js/3.11.1/av-min.js"></script>



<script src="//unpkg.com/valine/dist/Valine.min.js"></script>

<script>
  var GUEST = ['nick', 'mail', 'link'];
  var guest = 'nick,mail,link';
  guest = guest.split(',').filter(function(item) {
    return GUEST.indexOf(item) > -1;
  });
  new Valine({
    el: '#comments',
    verify: true,
    notify: true,
    appId: '1N5rpk874DGudJw2wCL9J011-gzGzoHsz',
    appKey: '9Y83e6suJgx567wtxhKy45IN',
    placeholder: 'Just go go',
    avatar: 'mm',
    meta: guest,
    pageSize: '10' || 10,
    visitor: true,
    lang: 'zk-cn' || 'zh-cn'
  });
</script>




  
    <script>
  window.livereOptions = {
    refer: '并发编程和线程池.html'
  };
  (function(d, s) {
    var j, e = d.getElementsByTagName(s)[0];
    if (typeof LivereTower === 'function') { return; }
    j = d.createElement(s);
    j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
    j.async = true;
    e.parentNode.insertBefore(j, e);
  })(document, 'script');
</script>

  


  
  <script>
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url).replace(/\/{2,}/g, '/');
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x"></i></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x"></i></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script>





  

  
  <script src="https://www.gstatic.com/firebasejs/4.6.0/firebase.js"></script>
  <script src="https://www.gstatic.com/firebasejs/4.6.0/firebase-firestore.js"></script>
  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.1/bluebird.core.min.js"></script>
  
  <script>
    (function () {

      firebase.initializeApp({
        apiKey: '',
        projectId: ''
      })

      function getCount(doc, increaseCount) {
        //increaseCount will be false when not in article page

        return doc.get().then(function (d) {
          var count
          if (!d.exists) { //has no data, initialize count
            if (increaseCount) {
              doc.set({
                count: 1
              })
              count = 1
            }
            else {
              count = 0
            }
          }
          else { //has data
            count = d.data().count
            if (increaseCount) {
              if (!(window.localStorage && window.localStorage.getItem(title))) { //if first view this article
                doc.set({ //increase count
                  count: count + 1
                })
                count++
              }
            }
          }
          if (window.localStorage && increaseCount) { //mark as visited
            localStorage.setItem(title, true)
          }

          return count
        })
      }

      function appendCountTo(el) {
        return function (count) {
          $(el).append(
            $('<span>').addClass('post-visitors-count').append(
              $('<span>').addClass('post-meta-divider').text('|')
            ).append(
              $('<span>').addClass('post-meta-item-icon').append(
                $('<i>').addClass('fa fa-users')
              )
              ).append($('<span>').text('阅读次数 ' + count))
          )
        }
      }

      var db = firebase.firestore()
      var articles = db.collection('articles')

      //https://hexo.io/docs/variables.html
      var isPost = '并发编程和线程池'.length > 0
      var isArchive = '' === 'true'
      var isCategory = ''.length > 0
      var isTag = ''.length > 0

      if (isPost) { //is article page
        var title = '并发编程和线程池'
        var doc = articles.doc(title)

        getCount(doc, true).then(appendCountTo($('.post-meta')))
      }
      else if (!isArchive && !isCategory && !isTag) { //is index page
        var titles = [] //array to titles

        var postsstr = '' //if you have a better way to get titles of posts, please change it
        eval(postsstr)

        var promises = titles.map(function (title) {
          return articles.doc(title)
        }).map(function (doc) {
          return getCount(doc)
        })
        Promise.all(promises).then(function (counts) {
          var metas = $('.post-meta')
          counts.forEach(function (val, idx) {
            appendCountTo(metas[idx])(val)
          })
        })
      }
    })()
  </script>


  
  

  
  

  


  
<script>
if ($('body').find('div.pdf').length) {
  $.ajax({
    type: 'GET',
    url: '//cdn.jsdelivr.net/npm/pdfobject@2/pdfobject.min.js',
    dataType: 'script',
    cache: true,
    success: function() {
      $('body').find('div.pdf').each(function(i, o) {
        PDFObject.embed($(o).attr('target'), $(o), {
          pdfOpenParams: {
            navpanes: 0,
            toolbar: 0,
            statusbar: 0,
            pagemode: 'thumbs',
            view: 'FitH'
          },
          PDFJS_URL: '/lib/pdf/web/viewer.html',
          height: $(o).attr('height') || '500px'
        });
      });
    },
  });
}
</script>


  
<script>
if ($('body').find('pre.mermaid').length) {
  $.ajax({
    type: 'GET',
    url: '//cdn.jsdelivr.net/npm/mermaid@8/dist/mermaid.min.js',
    dataType: 'script',
    cache: true,
    success: function() {
      mermaid.initialize({
        theme: 'dark',
        logLevel: 3,
        flowchart: { curve: 'linear' },
        gantt: { axisFormat: '%m/%d/%Y' },
        sequence: { actorMargin: 50 }
      });
    }
  });
}
</script>


  
  <script>
    (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      bp.src = (curProtocol === 'https') ? 'https://zz.bdstatic.com/linksubmit/push.js' : 'http://push.zhanzhang.baidu.com/push.js';
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
    })();
  </script>


  

  

  

  

  
  
  
  <script src="/lib/bookmark/bookmark.min.js?v=1.0"></script>
  <script>
  
    bookmark.scrollToMark('auto', "#更多");
  
  </script>


  
<script>
  $('.highlight').not('.gist .highlight').each(function(i, e) {
    var $wrap = $('<div>').addClass('highlight-wrap');
    $(e).after($wrap);
    $wrap.append($('<button>').addClass('copy-btn').append('复制').on('click', function(e) {
      var code = $(this).parent().find('.code').find('.line').map(function(i, e) {
        return $(e).text();
      }).toArray().join('\n');
      var ta = document.createElement('textarea');
      var yPosition = window.pageYOffset || document.documentElement.scrollTop;
      ta.style.top = yPosition + 'px'; // Prevent page scroll
      ta.style.position = 'absolute';
      ta.style.opacity = '0';
      ta.readOnly = true;
      ta.value = code;
      document.body.appendChild(ta);
      const selection = document.getSelection();
      const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false;
      ta.select();
      ta.setSelectionRange(0, code.length);
      ta.readOnly = false;
      var result = document.execCommand('copy');
      
        if (result) $(this).text('复制成功');
        else $(this).text('复制失败');
      
      ta.blur(); // For iOS
      $(this).blur();
      if (selected) {
        selection.removeAllRanges();
        selection.addRange(selected);
      }
    })).on('mouseleave', function(e) {
      var $b = $(this).find('.copy-btn');
      setTimeout(function() {
        $b.text('复制');
      }, 300);
    }).append(e);
  })
</script>


  

  

</body>
</html>
